home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1997 February / PC Plus Super CD (Issue 124) (PCP124-2-97) (February 1997).iso / handson / wilf / khamesh.bas < prev    next >
Encoding:
BASIC Source File  |  1997-01-31  |  88.3 KB  |  3,785 lines

  1. '<->
  2. DEFINT A-Z
  3. DECLARE SUB ziDragging ()
  4. ' Return if mouse active and still dragging, or else exhausted
  5.  
  6. DECLARE SUB ziDrawBank (FromButton, ToButton)
  7. ' Draw a bank of buttons (using Bank array)
  8.  
  9. DECLARE SUB ziExhaust ()
  10. ' Return when no keystrokes and no mouse buttons
  11.  
  12. DECLARE SUB ziLoadFont (Font$)
  13. ' Load a specified font
  14.  
  15. DECLARE SUB ziLocateMCursor (XCoord, YCoord)
  16. ' Locate mouse cursor to a named point
  17.  
  18. DECLARE SUB ziMouseOnButton (FromButton, ToButton)
  19. ' Sets FoundButton
  20.  
  21. DECLARE SUB ziPublish (Printstring$, size, italic)
  22. ' Print a string at graphics cursor (advanced)
  23. '   Size   = magnitude (per 8 pixels)
  24. '   Italic = +1 to make italic
  25. '          = +2 to make overprint (no background)
  26.  
  27. DECLARE SUB ziPublishHere (row, col, Printstring$, size, italic)
  28. ' Print a string at the specified text position
  29.  
  30. DECLARE SUB ziRadio (Button, FromButton, ToButton)
  31. ' Set one button in a Bank, resetting the rest
  32.  
  33. DECLARE SUB ziReadField (Min, Max, Permitted$)
  34. ' Read a field at the current TCursor location
  35. '   Permitted$ contains:
  36. '     * - any characters
  37. '     . - allow one full-stop (as decimal)
  38. '     A - auto-enter (when filled)
  39. '     C - capitalise letters
  40. '     E - ESC allowed to finish (skip) field
  41. '     J - justify (especially for numeric)
  42. '     N - numerics
  43. '     P - password-type display
  44. '     S - space
  45. '     X - alphabetic
  46. '     Y - Y or N (upper or lower)
  47.  
  48. DECLARE SUB ziSetMCursorVis (Status)
  49. ' Set visibility of mouse cursor
  50. '   Status = 0 for OFF
  51. '            1 for ON
  52. '            2 for ENQUIRE (set MCursorVis)
  53. '           10 for TEMPORARILY OFF
  54. '           11 for RESTORED (set MCursorVis)
  55.  
  56. DECLARE SUB ziWander (Timeout!)
  57. ' Timeout  = in seconds (0 = none)
  58. ' Response =   0 = (0:00) timed out
  59. '              n = (0:n)  displacement into Allowed$
  60.  
  61. ' key           &h01xx  &h02xx  &h04xx  &h08xx  &h10xx  &h20xx  &h40xx
  62. '                plain   CTRL    shift   Mouse    Fn   CTRL-Fn  shift-Fn
  63.  
  64. ' Enter      0    *       *       -      double    -      -       -
  65. ' (left)     1    *       *       -      left     F1     ^F1     +F1
  66. ' (right)    2    *       *       -      right    F2     ^F2     +F2
  67. ' (up)       3    *       -       -      both     F3     ^F3     +F3
  68. ' (down)     4    *       -       -    leftdrag   F4     ^F4     +F4
  69.  
  70. ' Backspace  5    *       *       -    rightdrag  F5     ^F5     +F5
  71. ' Home       6    *       *       -    bothdrag   F6     ^F6     +F6
  72. ' End        7    *       *       -       -       F7     ^F7     +F7
  73.  
  74. ' PgUP       8    *       *       -       -       F8     ^F8     +F8
  75. ' PgDN       9    *       *       -       -       F9     ^F9     +F9
  76.  
  77. ' Tab       10    *       -       *       -       F10    ^F10    +F10
  78. ' Escape    11    *       -       -       -       F11    ^F11    +F11
  79. '           12    -       -       -       -       F12    ^F12    +F12
  80.  
  81. ' Allowed$  = other allowed strokes
  82. ' (Note:  DClick is a flag permitting Double-clicks of mouse - slower!)
  83.  
  84. DEFINT A-Z
  85. DECLARE SUB zsAlignGCursor ()
  86. ' Align graphic cursor to same as text cursor
  87. '  - sets Row, Col, GXloc, GYloc
  88.  
  89. DECLARE SUB zsAlignTCursor ()
  90. ' Align text cursor to same as graphic cursor
  91. '  - sets Row, Col, GXloc, GYloc
  92.  
  93. DECLARE SUB zsLocateGCursor (XCoord, YCoord)
  94. ' Locate graphic cursor to a named point
  95.  
  96. DECLARE SUB zsPastel (XCoord, YCoord, Wide, Deep, colour1, colour2)
  97. ' Colour the defined oblong with a pastel mix of two colours
  98. '  Deep = 0 or 1 - square
  99. '       = n      - Y-pixel depth
  100.  
  101. DECLARE SUB zsSetScrnMode (Mode, HiRows, HiCols)
  102. ' Mode = 9 or 12
  103. ' HiRows = 1 to make high number of rows
  104. ' HiCols = 1 to make high number of cols (80)
  105. ' Set SCREEN parameters and blank the screen
  106. '  - sets ScrnMode, Xmax, Ymax, Rows, Cols, XYRatio!
  107. '  - uses FG and optionally BG (colours)
  108.  
  109. DECLARE SUB zsSubstitute (XCoord, YCoord, Wide, Deep, colour1, colour2)
  110. ' Substitute one colour with another within the defined oblong
  111. '  Deep = 0 or 1 - square
  112. '       = n      - Y-pixel depth
  113.  
  114. DECLARE SUB zzAlphaSort (Table$())
  115. ' Sort alphabetically the strings in the table; limited by " SortCount"
  116.  
  117. DECLARE SUB zzBasicInt (IntType)
  118. ' Execute interrupt (params in REGS.AX etc)
  119.  
  120. DECLARE SUB zzChangeDir (Directory$)
  121. ' Change to a particular directory
  122. '  -sets Directory$; eg "." will be changed to current directory
  123. ' if error occurs, Directory$ is returned as "?"
  124.  
  125. DECLARE SUB zzChangeDrive (Drive$)
  126. ' Change to a particular drive
  127. ' if Drive$ is empty on input, current drive is returned
  128. ' if error occurs, Drive$ is returned as "?"
  129.  
  130. DECLARE SUB zzCritOff ()
  131. ' turns off Critical Error Handling
  132.  
  133. DECLARE SUB zzCritOn ()
  134. ' restores normal Critical Error Handling
  135.  
  136. DECLARE SUB zzFileSelectBox (Pattern$)
  137. ' File Select Box function to choose an input file
  138.  
  139. DECLARE SUB zzInPath (Field$)
  140. ' Return full path to a file (in same string)
  141.  
  142. DECLARE SUB zzSearchD (Pattern$)
  143. ' Search for DIRECTORIES matching the pattern
  144. '  - sets Directories and Directories$()
  145.  
  146. DECLARE SUB zzSearchF (Pattern$)
  147. ' Search for FIILENAMES matching the pattern
  148. '  - sets FileNames and FileNames$()
  149.  
  150. DECLARE SUB zzValidate (Directory$)
  151. ' validate the named path and return its full
  152. '   (unqualified) name, including drive
  153. ' if error occcurs, Directory$ is returned as "?"
  154.  
  155. '================================================
  156. '/  UK copyright (c) 1997 by Future Publishing
  157. '/
  158. '/
  159. '/
  160. '/
  161. '================================================
  162. TYPE REGISTERS
  163.   AX AS INTEGER
  164.   BX AS INTEGER
  165.   CX AS INTEGER
  166.   DX AS INTEGER
  167.   DS AS INTEGER
  168.   SI AS INTEGER
  169.   ES AS INTEGER
  170.   DI AS INTEGER
  171.   FL AS INTEGER
  172. END TYPE
  173.  
  174. TYPE Buttons
  175.   Xloc AS INTEGER
  176.   Yloc AS INTEGER
  177.   Wide AS INTEGER
  178.   Deep AS INTEGER
  179. '  0 = checkbutton
  180. '  1 = square sculptured
  181. '  n = Y-pixels deep
  182.   State AS INTEGER
  183. '  0 = off
  184. '  1 = on
  185.   Active AS INTEGER
  186. '  0 = inactive
  187. '  1 = active
  188. END TYPE
  189.  
  190. CONST Pi! = 3.14159
  191. CONST Ex! = 2.71828
  192. CONST DegToRad! = .0174533
  193. CONST RadToDeg! = 57.2958
  194.  
  195. CONST ziNoShift = &H1
  196. CONST ziCTRL = &H2
  197. CONST ziShift = &H4
  198. CONST ziMouse = &H8
  199. CONST ziFn = &H10
  200. CONST ziCTRLFn = &H20
  201. CONST ziShiftFn = &H40
  202.  
  203. CONST ziL = 1
  204. CONST ziR = 2
  205. CONST ziUp = 3
  206. CONST ziDn = 4
  207. CONST ziBS = 5
  208. CONST ziHome = 6
  209. CONST ziEnd = 7
  210. CONST ziPgUp = 8
  211. CONST ziPgDn = 9
  212. CONST ziTab = 10
  213. CONST ziEsc = 11
  214.  
  215. CONST ziDbl = 0
  216. CONST ziBoth = 3
  217. CONST ziLDrag = 4
  218. CONST ziRDrag = 5
  219. CONST ziBothDrag = 6
  220.  
  221. DIM SHARED Regs AS REGISTERS
  222. DIM SHARED Bank(20) AS Buttons
  223. DIM SHARED Bad, Module$
  224. DIM SHARED Mouse, MCursorVis, MXloc, MYloc
  225. DIM SHARED DClick
  226. DIM SHARED ScrnMode, bg, fg, TCursor
  227. DIM SHARED Xmax, Ymax, GXloc, GYloc, XYratio!
  228. DIM SHARED Rows, Cols, row, col
  229. DIM SHARED Allowed$, Field$
  230. DIM SHARED FoundButton
  231. DIM SHARED Font(255, 7)
  232. DIM SHARED Response, HResponse, LResponse
  233. DIM SHARED SortCount
  234. REDIM SHARED Directories$(500)
  235. REDIM SHARED FileNames$(500)
  236. DIM SHARED Directories, FileNames
  237.  
  238. DIM SHARED IRET AS STRING * 3
  239. IRET = CHR$(&HB0) + CHR$(&H0) + CHR$(&HCF)
  240. DIM SHARED CritSeg, CritPtr, CritCount
  241.  
  242. '++++++++++++++++++++++++
  243. RANDOMIZE TIMER
  244. ON ERROR GOTO RESUMENEXT
  245. RESUMENEXT:
  246.   IF ERR = 255 THEN
  247.     CLS
  248.     BEEP
  249.     PRINT "Cannot find module "; Module$
  250.     SLEEP
  251.     SYSTEM
  252.   END IF
  253.   IF ERR THEN
  254.     Bad = ERR
  255.     RESUME NEXT
  256.   END IF
  257. Regs.AX = &H3524
  258. CALL zzBasicInt(&H21)
  259. CritSeg = Regs.ES
  260. CritPtr = Regs.BX
  261. '++++++++++++++++++++++++
  262. ' Test for presence of a mouse
  263. Mouse = 0
  264. Regs.AX = 0
  265. CALL zzBasicInt(&H33)
  266. IF Regs.AX THEN
  267.   Mouse = 1
  268.   CALL ziSetMCursorVis(0)
  269. END IF
  270. '++++++++++++++++++++++++
  271. ' Load the ASCII font
  272. CALL ziLoadFont("Ascii8x8")
  273. '/==================================/'
  274. '/  End of Standard Piecrust code   /'
  275. '/==================================/'
  276. '<+>
  277. '    ╔═════════════════════════════════════════════════════════════╗
  278. '    ║                                                             ║
  279. '    ║    Thanks to Ian Sharpe and Paul Grosse for suggestions     ║
  280. '    ║                    and corrections                          ║
  281. '    ║                                                             ║
  282. '    ╚═════════════════════════════════════════════════════════════╝
  283. '
  284. '
  285. '    ╔═════════════════════════════════════════════════════════════╗
  286. '    ║                                                             ║
  287. '    ║   Variables, constants and types                            ║
  288. '    ║                                                             ║
  289. '    ╚═════════════════════════════════════════════════════════════╝
  290. DIM Alpha(26)           'for display of macros (relates to KHAMESH.MAC)
  291.  
  292. DIM Points(7, 20, 2)    'all points of the nest of pentagons
  293.  
  294. DIM Hue(6)              'colour table for beads
  295. Hue(0) = 0              '(unused)
  296. Hue(1) = 2              'green
  297. Hue(2) = 14             'yellow
  298. Hue(3) = 65             'orange
  299. Hue(4) = 40             'red
  300. Hue(5) = 32             'blue
  301. Hue(6) = 0              'black
  302.  
  303. DIM Beads(8, 5)         'current status of beads (by position)
  304.             'note: only pentagons 2-7 used!
  305.  
  306. DIM Moves(999)          'history of last 1000 moves (0 is used)
  307.  
  308. Automatic = 0
  309. Animated = 1
  310. ScrambleDefault = 20
  311.  
  312. TYPE MacroRec           'format of records in KHAMESH.MAC
  313.  MacroLetter AS STRING * 1
  314.  MacroName AS STRING * 40
  315.  MacroMoves AS STRING * 99
  316. END TYPE
  317.  
  318. DIM FullRecord AS MacroRec
  319.  
  320. '    ╔═════════════════════════════════════════════════════════════╗
  321. '    ║                                                             ║
  322. '    ║   Find - or create - the KHAMESH.MAC file (one time only)   ║
  323. '    ║                                                             ║
  324. '    ╚═════════════════════════════════════════════════════════════╝
  325.  
  326. x$ = "KHAMESH.MAC"
  327. CALL zzInPath(x$)
  328. IF x$ = "" THEN
  329.  x$ = ".\KHAMESH.MAC"
  330.  OPEN x$ FOR RANDOM AS #1 LEN = 140
  331.  
  332.  FullRecord.MacroLetter = " "
  333.  FullRecord.MacroName = " "
  334.  FullRecord.MacroMoves = " "
  335.  
  336.  FOR i = 1 TO 26
  337.   PUT #1, i, FullRecord         'blank all records at first
  338.  NEXT
  339.  
  340. ' set up as 'unusable' all those records that correspond to functions
  341.  
  342.  functions$ = "AIOQRSU"
  343.  i = 1
  344.  DO
  345.   j = ASC(MID$(functions$, i, 1)) - 64
  346.   FullRecord.MacroLetter = CHR$(96 + j)
  347.   PUT #1, j, FullRecord
  348.   i = i + 1
  349.  LOOP UNTIL i > LEN(functions$)
  350.  
  351. ELSE
  352.  
  353.  OPEN x$ FOR RANDOM AS #1 LEN = 140
  354.  
  355. END IF
  356.  
  357. ' publish what macros there are (by looking at the MacroLetter of each
  358. ' record in KHAMESH.MAC)
  359.  
  360. GOSUB WhatMacros
  361.  
  362. '    ╔═════════════════════════════════════════════════════════════╗
  363. '    ║                                                             ║
  364. '    ║   Make calculations for setting up the screen initially     ║
  365. '    ║                                                             ║
  366. '    ╚═════════════════════════════════════════════════════════════╝
  367.  
  368. fg = 7: bg = 0
  369. CALL zsSetScrnMode(13, 0, 0)
  370.  
  371. ' POINT DETERMINATION: need only be done once!
  372. ' main points identify the five corners of each pentagon
  373. ' secondary points are halfway between these
  374. ' tertiary points are halfway again (between main and secondary points)
  375. ' secondary and tertiary points are used for placing beads during animation
  376.  
  377. DRAW "C0"
  378.  
  379. ' determine the main points (seven shells of five points)
  380.  
  381. FOR i = 1 TO 7
  382.  FOR j = 4 TO 20 STEP 4
  383.   CALL zsLocateGCursor(Xmax \ 2 + 35, Ymax \ 2 + 10)
  384.   DRAW "C0TA" + LTRIM$(STR$(18 * j - 54)) + "BR" + LTRIM$(STR$(18 * i - 5))
  385.   FOR k = 1 TO 2
  386.    Points(i, j, k) = POINT(k - 1)
  387.   NEXT
  388.  NEXT
  389. NEXT
  390.  
  391. ' determine the secondary points (five shells of five mid-points)
  392.  
  393. FOR i = 2 TO 6
  394.  FOR j = 4 TO 20 STEP 4
  395.   k = ((j \ 4) MOD 5) * 4 + 4
  396.   FOR m = 1 TO 2
  397.    Points(i, k - 2, m) = (Points(i, j, m) + Points(i, k, m)) \ 2
  398.   NEXT
  399.  NEXT
  400. NEXT
  401.  
  402. ' determine the tertiary points (five shells of another ten mid-points)
  403.  
  404. FOR i = 2 TO 6
  405.  FOR j = 2 TO 20 STEP 2
  406.   k = ((j \ 2) MOD 10) * 2 + 2
  407.   FOR m = 1 TO 2
  408.    Points(i, k - 1, m) = (Points(i, j, m) + Points(i, k, m)) \ 2
  409.   NEXT
  410.  NEXT
  411. NEXT
  412.  
  413. fg = 7: bg = 66
  414. CALL zsSetScrnMode(13, 0, 0)
  415. GOSUB RestoreBlock
  416.  
  417. ' colour all the regular beads
  418.  
  419. GOSUB ColourBeads
  420.  
  421. '    ╔═════════════════════════════════════════════════════════════╗
  422. '    ║                                                             ║
  423. '    ║  Handle keystrokes                                          ║
  424. '    ║                                                             ║
  425. '    ╚═════════════════════════════════════════════════════════════╝
  426. fg = 0
  427.  
  428. ' Here is the place we spend most of the time in the program: servicing
  429. ' keystrokes.
  430. '       A,a     - changes animation switch (initially ON)
  431. '       Q,esc   - permits 'QUIT' sequence
  432. '       R,r     - restart (all beads in correct place)
  433. '       S,s     - scramble (random moves)
  434. '       U,u     - undo last move (if still in history record)
  435. '       F1      - start a macro (or stop a macro)
  436. '       F2      - show a macro
  437. '
  438. '       also there are standard moves:
  439. '
  440. '       O       - rotate outer ring clockwise
  441. '       o       - rotate outer ring anticlockwise
  442. '       I       - rotate inner ring clockwise
  443. '       i       - rotate inner ring anticlockwise
  444. '     UParrow   - shuttle the columns inward
  445. '     DNarrow   - shuttle the columns outward
  446. '       *       - shuttle the columns in the opposite direction
  447.  
  448. DO
  449.  
  450. ' Beep whenever the user has got the beads in the correct places
  451. ' (black beads can be anywhere)
  452.  
  453.  IF Count <> 0 AND OldCount <> Count THEN
  454.   Ordered = -1
  455.   FOR j = 4 TO 20 STEP 4
  456.    OrderedHue = Hue(j \ 4)
  457.    FOR k = 3 TO 6
  458.    IF OrderedHue <> Hue(Beads(k, j \ 4)) THEN
  459.     Ordered = 0
  460.    END IF
  461.    NEXT
  462.   NEXT
  463.   IF Ordered THEN
  464.    BEEP: BEEP
  465.   END IF
  466.  END IF
  467.  OldCount = Count
  468.  
  469.  
  470.  GOSUB GetAKeystroke
  471.  Symbol$ = RIGHT$(key$, 1)
  472.  
  473.  SELECT CASE LEN(key$)
  474.  CASE 1
  475.  
  476.   SELECT CASE UCASE$(key$)
  477.  
  478.   CASE "A"      'change Animation
  479.  
  480.    Animated = 1 - Animated
  481.    IF Animated = 0 THEN
  482.     x$ = " "
  483.    ELSE
  484.     x$ = CHR$(251)
  485.    END IF
  486.    fg = 1: CALL ziPublishHere(2, 30, x$, 0, 1)
  487.  
  488.   CASE "Q", CHR$(27) 'quit
  489.  
  490.    fg = 0: bg = 48
  491.    x = Xmax \ 6: y = Ymax \ 4
  492.  
  493.    LINE (x + x, y)-(4 * x, y + y), bg, BF       'give option to quit
  494.    LINE (x + x, y)-(4 * x, y + y), 0, B
  495.    CALL ziPublishHere(8, 16, "Quit?", 2, 0)
  496.    CALL ziPublishHere(11, 18, "(Y/N)", 1, 0)
  497.  
  498.    DO
  499.     GOSUB GetAKeystroke
  500.     key$ = UCASE$(key$)
  501.     x = INSTR(CHR$(27) + "QqNnYy", key$)
  502.    LOOP UNTIL x > 0
  503.    IF x > 5 THEN
  504.     LINE (0, 0)-(Xmax, Ymax), 66, BF
  505.     SYSTEM
  506.    END IF
  507.    GOSUB RestoreBlock           'go back to normal running
  508.  
  509.   CASE "R"   'restart
  510.  
  511.    Recording = 0                'turn off any macro being recorded
  512.    GOSUB RecordingBlock
  513.    GOSUB WhatMacros
  514.  
  515.    GOSUB ResetCount             'reset the count and bead locations
  516.    GOSUB ColourBeads
  517.  
  518.   CASE "S"   'scramble
  519.  
  520.    fg = 0: bg = 48
  521.    x = Xmax \ 12: y = Ymax \ 8
  522.  
  523.    LINE (x, y + y)-(12 * x, 5 * y), bg, BF
  524.    LINE (x, y + y)-(12 * x, 5 * y), 0, B
  525.  
  526.    Shuffstr$ = RIGHT$(STR$(ScrambleDefault + 100), 2)
  527.    Shuff = VAL(Shuffstr$)
  528.  
  529.    CALL ziPublishHere(8, 18, "Scramble", 1, 0)
  530.    fg = 4: CALL ziPublishHere(10, 8, "How Many Moves?", 2, 0)
  531.    fg = 0: CALL ziPublishHere(13, 19, Shuffstr$, 3, 0)
  532.  
  533.    fg = 4: CALL ziPublishHere(14, 5, "PgUP/PgDN", 0, 0)
  534.    CALL ziPublishHere(14, 32, CHR$(24) + " / " + CHR$(25), 0, 0)
  535.  
  536.    fg = 0: CALL ziPublishHere(15, 8, CHR$(241) + "10", 0, 0)
  537.    CALL ziPublishHere(15, 33, CHR$(241) + "1", 0, 0)
  538.  
  539.    DO
  540.     GOSUB GetAKeystroke
  541.     key$ = UCASE$(key$)
  542.  
  543.     SELECT CASE LEN(key$)
  544.    
  545.     CASE 1
  546.      SELECT CASE ASC(key$)
  547.  
  548.      CASE 13    'Enter
  549.       ScrambleDefault = VAL(Shuffstr$)
  550.       Shuff = ScrambleDefault
  551.       EXIT DO
  552.  
  553.      CASE 27    'Escape
  554.       Shuff = 0
  555.       EXIT DO
  556.  
  557.      END SELECT
  558.     
  559.     CASE 2
  560.  
  561.      SELECT CASE ASC(RIGHT$(key$, 1))
  562.  
  563.      CASE 72    'Up
  564.       x = 1
  565.      
  566.      CASE 73    'Page Up
  567.       x = 10
  568.  
  569.      CASE 80    'Down
  570.       IF Shuff = 1 THEN
  571.        x = 98
  572.       ELSE
  573.        x = 99
  574.       END IF
  575.  
  576.      CASE 81    'Page Down
  577.       x = 90
  578.  
  579.      CASE ELSE
  580.       x = 0
  581.  
  582.      END SELECT
  583.     
  584.      IF x <> 0 THEN
  585.  
  586.       Shuff = (Shuff + x) MOD 100
  587.       IF Shuff = 0 THEN
  588.        Shuff = 1
  589.       END IF
  590.       Shuffstr$ = RIGHT$(STR$(Shuff + 100), 2)
  591.       CALL ziPublishHere(13, 19, Shuffstr$, 3, 0)
  592.  
  593.      END IF
  594.     
  595.     END SELECT
  596.   
  597.    LOOP
  598.  
  599.    GOSUB RestoreBlock
  600.  
  601.  
  602.    IF Shuff THEN
  603.  
  604.     Recording = 0
  605.     bg = 66
  606.     GOSUB RecordingBlock
  607.     GOSUB WhatMacros
  608.  
  609.     GOSUB ResetCount
  610.  
  611.     Automatic = 1
  612.  
  613.     FOR RndCount = 1 TO Shuff
  614.  
  615.      x = INT(RND * 3)
  616.      IF x = 0 THEN
  617.             GOSUB UpDownArrow
  618.      ELSE
  619.       Outer = x - 1
  620.       Clockwise = Outer
  621.       GOSUB MoveBeads
  622.      END IF
  623.  
  624.     NEXT
  625.  
  626.     Automatic = 0
  627.     GOSUB ReColourBeads
  628.  
  629.    END IF
  630.  
  631.  
  632.   CASE "U"      'undo
  633.  
  634.    Recording = 0                'turn off any macro being recorded
  635.    GOSUB RecordingBlock
  636.    GOSUB WhatMacros
  637.  
  638.    IF Count <> 0 THEN
  639.  
  640.     i = Count MOD 1000          'delve into the history to get last move
  641.     key$ = CHR$(Moves(i))
  642.     IF ASC(key$) <> 0 THEN
  643.      Moves(i) = 0               'if move is available, run it "backward"
  644.      Count = Count - 2
  645.      GOSUB BackwardMove
  646.     END IF
  647.  
  648.    END IF
  649.  
  650.   CASE "O", "I", "*"            'NORMAL moves
  651.  
  652.    GOSUB ForwardMove            'perform a normal move
  653.    GOSUB RecordMove             'record it if a macro is on
  654.  
  655.   CASE ELSE     'macros
  656.  
  657.    IF INSTR(Macros$, UCASE$(key$)) THEN
  658.  
  659.     Recording = 0               'no macros within macros, so turn off!
  660.     GOSUB RecordingBlock
  661.     GOSUB WhatMacros
  662.  
  663.     GOSUB MacroBody             'perform the macro
  664.    END IF
  665.  
  666.   END SELECT
  667.  
  668.  CASE 2
  669.  
  670.   SELECT CASE MID$(key$, 2)     'for 'long' responses, select second byte
  671.  
  672.   CASE "H", "P" 'up arrow, down arrow
  673.  
  674.    key$ = "*"
  675.    Symbol$ = "*"
  676.    GOSUB ForwardMove            'perform the move
  677.    GOSUB RecordMove             'record it if a macro is on
  678.  
  679.   CASE CHR$(59) 'F1 key
  680.  
  681.    IF Recording = 0 THEN        'START a macro
  682.  
  683.     GOSUB WhichMacro            'ask "Which Macro?"
  684.     fg = 0: CALL ziPublishHere(8, 16, "Start Macro", 1, 0)
  685.  
  686.     DO
  687.      GOSUB GetAKeystroke
  688.      Chosen$ = UCASE$(key$)     'here is the chosen macro letter
  689.      x = INSTR(Macros$ + Available$ + CHR$(27), Chosen$)
  690.     LOOP UNTIL x > 0            'check that this letter is allowable
  691.  
  692.     IF ASC(Chosen$) <> 27 THEN          'if not escape, continue
  693.  
  694.      IF INSTR(Macros$, Chosen$) > 0 THEN
  695.  
  696.       bg = 48                           'this macro exists!
  697.  
  698.       x = Xmax \ 6: y = Ymax \ 4
  699.       LINE (x, y)-(5 * x, y + y), bg, BF
  700.       LINE (x, y)-(5 * x, y + y), 0, B
  701.       CALL ziPublishHere(8, 9, "Overwrite " + Chosen$ + "?", 2, 0)
  702.       CALL ziPublishHere(11, 18, "(Y/N)", 1, 0)
  703.  
  704.       DO
  705.        GOSUB GetAKeystroke
  706.        key$ = UCASE$(key$)
  707.        x = INSTR(CHR$(27) + "QqNnYy", key$)
  708.       LOOP UNTIL x > 0
  709.       IF x > 5 THEN
  710.  
  711. ' now we must expunge the record of any EARLIER use of this macro
  712. ' (to prevent "Undoing" the old contents)
  713.  
  714.        x = Count MOD 1000
  715.        FOR i = 0 TO x
  716.     IF UCASE$(CHR$(Moves(i))) = Chosen$ THEN
  717.      FOR j = i TO 0 STEP -1
  718.       Moves(j) = 0
  719.      NEXT
  720.      FOR j = 999 TO x STEP -1
  721.       IF j <> x THEN
  722.        Moves(j) = 0
  723.       END IF
  724.      NEXT
  725.     END IF
  726.        NEXT
  727.  
  728. ' rewrite the MAC record to indicate that this macro is now empty
  729.  
  730.        GOSUB EmptyMacro
  731.      
  732.       ELSE
  733.       
  734.        Chosen$ = CHR$(27)
  735.      
  736.       END IF
  737.  
  738.      ELSE
  739.  
  740. ' make sure this macro is now empty
  741.  
  742.       GOSUB EmptyMacro
  743.  
  744.      END IF
  745.  
  746.     END IF
  747.  
  748.     IF Chosen$ <> CHR$(27) THEN
  749.  
  750.      Recording = 1              'from now on, we are recording!
  751.      GOSUB RecordingBlock
  752.  
  753.     ELSE
  754.  
  755.      GOSUB RestoreBlock
  756.  
  757.     END IF
  758.  
  759.    ELSE         'STOP MACRO is chosen
  760.  
  761.     Recording = 0               'simply reset the Recording flag..
  762.     GOSUB RecordingBlock        '..and turn off the block
  763.     GOSUB WhatMacros            're-establish the macro list
  764.  
  765.    END IF
  766.  
  767.   CASE CHR$(60) 'F2 key: DISPLAY MACRO
  768.  
  769.    GOSUB WhichMacro
  770.    fg = 0: CALL ziPublishHere(8, 16, "Show Macro", 1, 0)
  771.  
  772.    DO                           'find out which macro to display
  773.     GOSUB GetAKeystroke
  774.     key$ = UCASE$(key$)
  775.     x = INSTR(Macros$ + CHR$(27), key$)
  776.    LOOP UNTIL x > 0
  777.  
  778.    IF ASC(key$) <> 27 THEN
  779.  
  780.     bg = 48: GOSUB StartScreen          'change the screen
  781.     fg = 0: CALL ziPublishHere(2, 20, "Macro ", 2, 0)
  782.     CALL ziPublish(key$, 2, 0)
  783.  
  784.     RecordNumber = ASC(UCASE$(key$)) - 64
  785.     GET #1, RecordNumber, FullRecord
  786.  
  787. ' display the actual macro
  788.  
  789.     fg = 7
  790.     FOR i = 1 TO 99
  791.      row = (i - 1) MOD 20 + 6
  792.      col = ((i - 1) \ 20) * 8 + 2
  793.      x$ = RIGHT$(STR$(100 + i), 2)
  794.      y$ = MID$(FullRecord.MacroMoves, i, 1)
  795.      IF y$ = " " THEN
  796.       fg = 7
  797.      ELSE
  798.       fg = 0
  799.      END IF
  800.      CALL ziPublishHere(row, col, x$, 1, 0)
  801.      fg = 4: CALL ziPublish("  " + y$, 1, 0)
  802.     NEXT
  803.  
  804. ' show the name (and allow editing)
  805.  
  806.     disp = 1: newdisp = 1
  807.     fg = 8: CALL ziPublishHere(4, 1, FullRecord.MacroName, 1, 2)
  808.     DO
  809.      CALL ziPublishHere(5, disp, "^", 1, 0)
  810.      GOSUB GetAKeystroke
  811.  
  812.      IF LEN(key$) = 1 THEN
  813.  
  814.       SELECT CASE key$
  815.  
  816.       CASE CHR$(8)      'backspace
  817.        MID$(FullRecord.MacroName, disp, 1) = " "
  818.        fg = 8: CALL ziPublishHere(4, disp, " ", 1, 0)
  819.        newdisp = (disp + 38) MOD 40 + 1
  820.  
  821.       CASE CHR$(13)     'return
  822.        PUT #1, RecordNumber, FullRecord
  823.        EXIT DO
  824.  
  825.       CASE CHR$(27)     'escape
  826.        EXIT DO
  827.  
  828.       CASE " " TO "z"
  829.        IF LEN(key$) = 1 THEN
  830.     MID$(FullRecord.MacroName, disp, 1) = key$
  831.     fg = 8: CALL ziPublishHere(4, disp, key$, 1, 0)
  832.        END IF
  833.        newdisp = disp MOD 40 + 1
  834.  
  835.       END SELECT
  836.  
  837.      ELSE
  838.  
  839.       x = ASC(RIGHT$(key$, 1))
  840.       SELECT CASE x
  841.  
  842.       CASE 71   'home
  843.        newdisp = 1
  844.  
  845.       CASE 79   'end
  846.        newdisp = 41
  847.        DO
  848.     newdisp = newdisp - 1
  849.     IF MID$(FullRecord.MacroName, newdisp, 1) <> " " THEN
  850.      EXIT DO
  851.     END IF
  852.     IF newdisp = 1 THEN
  853.      newdisp = 0
  854.      EXIT DO
  855.     END IF
  856.        LOOP
  857.        IF newdisp < 40 THEN
  858.     newdisp = newdisp + 1
  859.        END IF
  860.  
  861.       CASE 75   'left arrow
  862.        newdisp = (disp + 38) MOD 40 + 1
  863.  
  864.       CASE 77   'right arrow
  865.        newdisp = disp MOD 40 + 1
  866.  
  867.       CASE 82   'insert
  868.        newdisp = disp
  869.        IF disp < 40 THEN
  870.     FOR i = 39 TO disp STEP -1
  871.      x$ = MID$(FullRecord.MacroName, i, 1)
  872.      MID$(FullRecord.MacroName, i + 1, 1) = x$
  873.     NEXT
  874.        END IF
  875.        MID$(FullRecord.MacroName, disp, 1) = " "
  876.        CALL ziPublishHere(4, 1, FullRecord.MacroName, 1, 0)
  877.  
  878.       CASE 83   'delete
  879.        newdisp = disp
  880.        IF disp < 40 THEN
  881.     FOR i = disp TO 39
  882.      x$ = MID$(FullRecord.MacroName, i + 1, 1)
  883.      MID$(FullRecord.MacroName, i, 1) = x$
  884.     NEXT
  885.        END IF
  886.        MID$(FullRecord.MacroName, 40, 1) = " "
  887.        CALL ziPublishHere(4, 1, FullRecord.MacroName, 1, 0)
  888.  
  889.       END SELECT
  890.  
  891.      END IF
  892.  
  893.      CALL ziPublishHere(5, disp, " ", 1, 0)
  894.      disp = newdisp
  895.     LOOP
  896.  
  897.    END IF
  898.  
  899. ' return to working screen
  900.  
  901.    GOSUB RestoreBlock
  902.  
  903.   END SELECT
  904.  
  905.  END SELECT
  906.  
  907. LOOP
  908. '<p>
  909. '    ╔═════════════════════════════════════════════════════════════╗
  910. '    ║                                                             ║
  911. '    ║         ╔══ ╦ ╦ ╦═╗ ╦═╗ ╔═╗ ╦ ╦ ═╦═ ╦ ╦═╗ ╔══ ╔══           ║
  912. '    ║         ╚═╗ ║ ║ ╠═╣ ╠╦╝ ║ ║ ║ ║  ║  ║ ║ ║ ╠═  ╚═╗           ║
  913. '    ║         ══╝ ╚═╝ ╩═╝ ╝╚═ ╚═╝ ╚═╝  ╩  ╩ ╩ ╩ ╚══ ══╝           ║
  914. '    ║                                                             ║
  915. '    ╚═════════════════════════════════════════════════════════════╝
  916.  
  917. '   ╔════════════╗
  918. '   ║ AddToCount ╟─────────────────────────────────────────────────┐
  919. '   ╚╤═══════════╝                                                 │
  920. '    │   Add one to the counter displayed on the screen and        │
  921. '    │   tidy the history                                          │
  922. '    │                                                             │
  923. '    └─────────────────────────────────────────────────────────────┘
  924. AddToCount:
  925.  
  926.  IF Expanding = 0 THEN
  927.  
  928.   Count = Count + 1
  929.   x$ = RIGHT$("00000" + MID$(STR$(Count), 2), 6)
  930.   fg = 0: CALL ziPublishHere(5, 34, x$, 0, 0)
  931.   i = Count MOD 1000
  932.   IF Moves(i) = 0 THEN
  933.    Moves(i) = ASC(Symbol$)
  934.   END IF
  935.   i = (i + 1) MOD 1000
  936.   Moves(i) = 0
  937.  
  938.  END IF
  939.  RETURN
  940. '<p>
  941. '   ╔════════════╗
  942. '   ║  Alphabet  ╟─────────────────────────────────────────────────┐
  943. '   ╚╤═══════════╝                                                 │
  944. '    │   Go through the alphabet and publish what are MACROS       │
  945. '    │                                                             │
  946. '    └─────────────────────────────────────────────────────────────┘
  947. Alphabet:
  948.  
  949.  fg = 7: bg = 15
  950.  CALL ziPublishHere(18, 3, " ABCDEFGH ", 0, 0)
  951.  CALL ziPublishHere(19, 3, "IJKLMNOPQ ", 0, 0)
  952.  CALL ziPublishHere(20, 3, "RSTUVWXYZ ", 0, 0)
  953.  fg = 0: bg = 66
  954.  CALL ziPublishHere(17, 5, "macros", 0, 1)
  955.  
  956.  Macros$ = ""
  957.  Available$ = ""
  958.  FOR i = 1 TO 26
  959.   j = 18 + i \ 9
  960.   k = i MOD 9 + 3
  961.   SELECT CASE Alpha(i)
  962.  
  963.   CASE 0
  964.    Available$ = Available$ + CHR$(64 + i)
  965.  
  966.   CASE 1
  967.    fg = 4: CALL ziPublishHere(j, k, CHR$(64 + i), 0, 2)
  968.    Macros$ = Macros$ + CHR$(64 + i)
  969.  
  970.   CASE 2
  971.    fg = 7: bg = 15: CALL ziPublishHere(j, k, CHR$(249), 0, 0)
  972.  
  973.   END SELECT
  974.  
  975.  NEXT
  976.  fg = 0: bg = 66
  977.  RETURN
  978. '<p>
  979. '   ╔═══════════════════╗
  980. '   ║   BackwardMove    ╟──────────────────────────────────────────┐
  981. '   ╚╤══════════════════╝                                          │
  982. '    │      Make a "backward" move                                 │
  983. '    │                                                             │
  984. '    └─────────────────────────────────────────────────────────────┘
  985. BackwardMove:
  986.  
  987.  x = INSTR("IiOo*", key$)
  988.  IF x > 0 THEN
  989.  
  990.   key$ = MID$("iIoO*", x, 1)
  991.   GOSUB ForwardMove
  992.  
  993.  ELSE
  994.  
  995.   IF INSTR(Macros$, UCASE$(key$)) THEN
  996.  
  997.    key$ = CHR$(ASC(key$) XOR 32)        'swap direction of macro
  998.    GOSUB MacroBody
  999.  
  1000.   END IF
  1001.  
  1002.  END IF
  1003.  RETURN
  1004. '<p>
  1005. '   ╔═══════════════════╗
  1006. '   ║   ColourBeads     ╟──────────────────────────────────────────┐
  1007. '   ╚╤══════════════════╝                                          │
  1008. '    │   Colour the beads as at the start of the puzzle            │
  1009. '    │                                                             │
  1010. '    └─────────────────────────────────────────────────────────────┘
  1011. ColourBeads:
  1012.  
  1013.  FOR i = 3 TO 6
  1014.   FOR j = 4 TO 20 STEP 4
  1015.    Beads(i, j \ 4) = j \ 4
  1016.   NEXT
  1017.  NEXT
  1018.  
  1019.  FOR i = 1 TO 5
  1020.   Beads(7, i) = 0
  1021.  NEXT
  1022.  
  1023.  FOR i = 5 TO 11 STEP 3
  1024.   Beads(2, i \ 2) = 6
  1025.  NEXT
  1026.  
  1027.  GOSUB ReColourBeads
  1028.  
  1029.  RETURN
  1030. '<p>
  1031. '   ╔═══════════════════╗
  1032. '   ║    EmptyMacro     ╟──────────────────────────────────────────┐
  1033. '   ╚╤══════════════════╝                                          │
  1034. '    │  Empty the chosen macro, resetting it to available          │
  1035. '    │                                                             │
  1036. '    └─────────────────────────────────────────────────────────────┘
  1037. EmptyMacro:
  1038.  x = ASC(Chosen$) - 64
  1039.  Alpha(x) = 0
  1040.  FullRecord.MacroLetter = " "
  1041.  FullRecord.MacroName = " "
  1042.  FullRecord.MacroMoves = " "
  1043.  PUT #1, x, FullRecord
  1044.  
  1045.  GOSUB RestoreBlock
  1046.  
  1047.  RETURN
  1048. '<p>
  1049. '   ╔═══════════════════╗
  1050. '   ║   ForwardMove     ╟──────────────────────────────────────────┐
  1051. '   ╚╤══════════════════╝                                          │
  1052. '    │  Move rings or shuttle the columns                          │
  1053. '    │  (I, i, O, o, UParrow, DNarrow)                             │
  1054. '    │                                                             │
  1055. '    └─────────────────────────────────────────────────────────────┘
  1056. ForwardMove:
  1057.  
  1058.  SELECT CASE UCASE$(key$)
  1059.  
  1060.  CASE "I", "O" 'move a ring
  1061.  
  1062.   Outer = INSTR("O", UCASE$(key$))
  1063.   IF key$ = UCASE$(key$) THEN
  1064.    Clockwise = 1
  1065.   ELSE
  1066.    Clockwise = 0
  1067.   END IF
  1068.   GOSUB AddToCount
  1069.   GOSUB MoveBeads
  1070.  
  1071.  CASE "*"       'arrow move
  1072.  
  1073.   GOSUB UpDownArrow
  1074.   GOSUB AddToCount
  1075.  
  1076.  END SELECT
  1077.  
  1078.  RETURN
  1079. '<p>
  1080. '   ╔═══════════════════╗
  1081. '   ║   GetAKeystroke   ╟──────────────────────────────────────────┐
  1082. '   ╚╤══════════════════╝                                          │
  1083. '    │  Obtain a buffered keystroke in "key$"                      │
  1084. '    │                                                             │
  1085. '    └─────────────────────────────────────────────────────────────┘
  1086. GetAKeystroke:
  1087.  key$ = "X"
  1088.  DO UNTIL LEN(key$) = 0
  1089.   key$ = INKEY$
  1090.  LOOP
  1091.  DO WHILE LEN(key$) = 0
  1092.   key$ = INKEY$
  1093.  LOOP
  1094.  RETURN
  1095. '<p>
  1096. '   ╔═══════════════════╗
  1097. '   ║    MacroBody      ╟──────────────────────────────────────────┐
  1098. '   ╚╤══════════════════╝                                          │
  1099. '    │   Expand the body of a macro and execute its parts          │
  1100. '    │                                                             │
  1101. '    └─────────────────────────────────────────────────────────────┘
  1102. MacroBody:
  1103.  
  1104.  OSymbol$ = Symbol$
  1105.  LINE (1, 102)-(87, 128), 1, BF
  1106.  fg = 15: CALL ziPublishHere(14, 3, "Playing", 0, 2)
  1107.  CALL ziPublishHere(15, 5, key$, 2, 2)
  1108.  
  1109.  Expanding = 1
  1110.  i = ASC(UCASE$(key$)) - 64
  1111.  GET #1, i, FullRecord
  1112.  
  1113.  IF key$ = UCASE$(key$) THEN
  1114.  
  1115.   FOR MacroPoint = 1 TO 99
  1116.    key$ = MID$(FullRecord.MacroMoves, MacroPoint, 1)
  1117.    IF key$ = " " THEN EXIT FOR
  1118.    GOSUB ForwardMove
  1119.   NEXT
  1120.  
  1121.  ELSE
  1122.  
  1123.   FOR MacroPoint = 99 TO 1 STEP -1
  1124.    key$ = MID$(FullRecord.MacroMoves, MacroPoint, 1)
  1125.    IF key$ <> " " THEN
  1126.     GOSUB BackwardMove
  1127.    END IF
  1128.   NEXT
  1129.  END IF
  1130.  
  1131.  Expanding = 0
  1132.  
  1133.  Symbol$ = OSymbol$
  1134.  GOSUB AddToCount
  1135.  LINE (1, 102)-(87, 128), bg, BF
  1136.  
  1137.  RETURN
  1138. '<p>
  1139. '   ╔═══════════════════╗
  1140. '   ║    MoveBeads      ╟──────────────────────────────────────────┐
  1141. '   ╚╤══════════════════╝                                          │
  1142. '    │    Establish the "before" and "after" configurations        │
  1143. '    │    of the beads, then call for animation                    │
  1144. '    │                                                             │
  1145. '    └─────────────────────────────────────────────────────────────┘
  1146. MoveBeads:
  1147.  
  1148.  x = Outer + Outer
  1149.  y = 5 - 4 * Clockwise
  1150.  i = Beads(x + 3, y)
  1151.  j = Beads(x + 4, y)
  1152.  FOR k = 1 TO 4
  1153.   FOR m = 3 TO 4
  1154.    IF Clockwise = 0 THEN
  1155.     Beads(m + x, 6 - k) = Beads(m + x, 5 - k)
  1156.    ELSE
  1157.     Beads(m + x, k) = Beads(m + x, k + 1)
  1158.    END IF
  1159.   NEXT
  1160.  NEXT
  1161.  Beads(x + 3, 6 - y) = i
  1162.  Beads(x + 4, 6 - y) = j
  1163.  
  1164.  A = 3 + 2 * Outer
  1165.  
  1166.  ' turn off the MAIN beads
  1167.  
  1168.  IF Automatic = 0 THEN
  1169.   IF Animated = 1 THEN
  1170.    FOR j = 4 TO 20 STEP 4
  1171.     FOR k = A TO A + 1
  1172.      IF j = 4 OR j = 12 THEN
  1173.       IF Outer = 0 THEN
  1174.        Shade = &H50
  1175.       ELSE
  1176.        Shade = 15
  1177.       END IF
  1178.      ELSE
  1179.       Shade = 7
  1180.      END IF
  1181.      FOR m = 1 TO 2
  1182.       coord(m) = (Points(k, j, m) + Points(k - 1, j, m)) \ 2
  1183.      NEXT
  1184.      PAINT (coord(1), coord(2)), Shade, Shade
  1185.     NEXT
  1186.    NEXT
  1187.  
  1188. ' turn on interim beads
  1189.  
  1190.    FOR i = 3 TO 1 STEP -1
  1191.  
  1192.     FOR j = 4 TO 20 STEP 4
  1193.      FOR k = A TO A + 1
  1194.       IF Outer = 0 THEN
  1195.        Shade = &H50
  1196.       ELSE
  1197.        Shade = 15
  1198.       END IF
  1199.       IF Clockwise = 0 THEN
  1200.        m = j - i
  1201.       ELSE
  1202.       m = (j + i) MOD 20
  1203.       END IF
  1204.       FOR n = 1 TO 2
  1205.        coord(n) = (Points(k, m, n) + Points(k - 1, m, n)) \ 2
  1206.       NEXT
  1207.       CIRCLE (coord(1), coord(2)), 2, 8
  1208.  
  1209.       IF Clockwise = 0 THEN
  1210.        PAINT (coord(1), coord(2)), Hue(Beads(k, (m \ 4 + 5) MOD 5 + 1)), 8
  1211.       ELSE
  1212.        PAINT (coord(1), coord(2)), Hue(Beads(k, (m \ 4 + 4) MOD 5 + 1)), 8
  1213.       END IF
  1214.  
  1215.      NEXT
  1216.     NEXT
  1217.  
  1218.     PLAY "MBL64N0N0"
  1219.     DO: LOOP UNTIL PLAY(0) = 0
  1220.  
  1221.     FOR j = 4 TO 20 STEP 4
  1222.      FOR k = A TO A + 1
  1223.       FOR m = 1 TO 2
  1224.        IF Clockwise = 0 THEN
  1225.     n = j - i
  1226.        ELSE
  1227.     n = (j + i) MOD 20
  1228.        END IF
  1229.        coord(m) = (Points(k, n, m) + Points(k - 1, n, m)) \ 2
  1230.       NEXT
  1231.       PAINT (coord(1), coord(2)), Shade, Shade
  1232.      NEXT
  1233.     NEXT
  1234.    NEXT
  1235.  
  1236.   END IF
  1237.  END IF
  1238.  
  1239. ' turn on final MAIN beads
  1240.  
  1241.  FOR j = 4 TO 20 STEP 4
  1242.   FOR k = A TO A + 1
  1243.    FOR m = 1 TO 2
  1244.     coord(m) = (Points(k, j, m) + Points(k - 1, j, m)) \ 2
  1245.    NEXT
  1246.  
  1247.    IF Automatic = 0 THEN
  1248.     CIRCLE (coord(1), coord(2)), 2, 8
  1249.     PAINT (coord(1), coord(2)), Hue(Beads(k, j \ 4)), 8
  1250.    END IF
  1251.  
  1252.   NEXT
  1253.  NEXT
  1254.  
  1255.  RETURN
  1256. '<p>
  1257. '   ╔═══════════════════╗
  1258. '   ║   ReColourBeads   ╟──────────────────────────────────────────┐
  1259. '   ╚╤══════════════════╝                                          │
  1260. '    │  Restore the colours of the beads to the current state      │
  1261. '    │                                                             │
  1262. '    └─────────────────────────────────────────────────────────────┘
  1263. ReColourBeads:
  1264.  
  1265.  FOR i = 3 TO 6
  1266.   FOR j = 4 TO 20 STEP 4
  1267.    FOR m = 1 TO 2
  1268.     coord(m) = (Points(i, j, m) + Points(i - 1, j, m)) \ 2
  1269.    NEXT
  1270.    CIRCLE (coord(1), coord(2)), 2, 8
  1271.    PAINT (coord(1), coord(2)), Hue(Beads(i, j \ 4)), 8
  1272.   NEXT
  1273.  NEXT
  1274.  
  1275.  fg = 0
  1276.  GOSUB SetArrows
  1277.  
  1278.  RETURN
  1279. '<p>
  1280. '   ╔═══════════════════╗
  1281. '   ║  RecordingBlock   ╟──────────────────────────────────────────┐
  1282. '   ╚╤══════════════════╝                                          │
  1283. '    │  Handle the "Recording" block - whether or not it appears   │
  1284. '    │                                                             │
  1285. '    └─────────────────────────────────────────────────────────────┘
  1286. RecordingBlock:
  1287.  IF Recording = 1 THEN
  1288.  
  1289.   LINE (1, 102)-(87, 128), 4, BF
  1290.   LINE (1, 102)-(87, 128), 0, B
  1291.   fg = 15: CALL ziPublishHere(14, 2, "Recording", 0, 2)
  1292.   CALL ziPublishHere(15, 5, Chosen$, 2, 2)
  1293.   fg = 0: CALL ziPublishHere(22, 7, "stop ", 0, 0)
  1294.  
  1295.  ELSE
  1296.  
  1297.   LINE (1, 102)-(87, 128), bg, BF
  1298.   fg = 0: CALL ziPublishHere(22, 7, "start", 0, 0)
  1299.  
  1300.  END IF
  1301.  
  1302.  RETURN
  1303. '<p>
  1304. '   ╔═══════════════════╗
  1305. '   ║    RecordMove     ╟──────────────────────────────────────────┐
  1306. '   ╚╤══════════════════╝                                          │
  1307. '    │  If recording a macro, record the move just performed       │
  1308. '    │                                                             │
  1309. '    └─────────────────────────────────────────────────────────────┘
  1310. RecordMove:
  1311.  IF Recording = 1 THEN
  1312.  
  1313.   FullRecord.MacroLetter = UCASE$(Chosen$)
  1314.  
  1315.   x$ = RTRIM$(FullRecord.MacroMoves)
  1316.   FullRecord.MacroMoves = x$ + key$
  1317.   PUT #1, ASC(UCASE$(Chosen$)) - 64, FullRecord
  1318.   IF LEN(x$) = 99 THEN
  1319.    Recording = 0
  1320.    GOSUB RecordingBlock
  1321.    GOSUB WhatMacros
  1322.   END IF
  1323.  
  1324.  END IF
  1325.  RETURN
  1326. '<p>
  1327. '   ╔═══════════════════╗
  1328. '   ║    ResetCount     ╟──────────────────────────────────────────┐
  1329. '   ╚╤══════════════════╝                                          │
  1330. '    │   Rest the count to zero and clear the history              │
  1331. '    │                                                             │
  1332. '    └─────────────────────────────────────────────────────────────┘
  1333. ResetCount:
  1334.  
  1335.  FOR i = 0 TO 999
  1336.   Moves(i) = 0
  1337.  NEXT
  1338.  Count = 0
  1339.  fg = 0: CALL ziPublishHere(5, 34, "000000", 0, 0)
  1340.  
  1341.  RETURN
  1342. '<p>
  1343. '   ╔════════════════╗
  1344. '   ║  RestoreBlock  ╟─────────────────────────────────────────────┐
  1345. '   ╚╤═══════════════╝                                             │
  1346. '    │  Restore the block used to run "quit" and "macro" options   │
  1347. '    │                                                             │
  1348. '    └─────────────────────────────────────────────────────────────┘
  1349. RestoreBlock:
  1350.  bg = 66
  1351.  GOSUB StartScreen
  1352.  
  1353.  IF Animated = 0 THEN
  1354.   x$ = " "
  1355.  ELSE
  1356.   x$ = CHR$(251)
  1357.  END IF
  1358.  fg = 1: CALL ziPublishHere(2, 30, x$, 0, 1)
  1359.  fg = 0
  1360.  
  1361.  GOSUB Alphabet
  1362.  
  1363. ' colour the end-indicators
  1364.  
  1365.  FOR i = 4 TO 20 STEP 4
  1366.   CIRCLE (Points(7, i, 1), Points(7, i, 2)), 8, 0
  1367.   PAINT (Points(7, i, 1), Points(7, i, 2)), Hue(i \ 4), 0
  1368.  NEXT
  1369.  
  1370. ' join the points
  1371.  
  1372.  FOR i = 1 TO 7
  1373.   FOR j = 4 TO 20 STEP 4
  1374.    k = ((j \ 4) MOD 5) * 4 + 4
  1375.    LINE (Points(i, j, 1), Points(i, j, 2))-(Points(i, k, 1), Points(i, k, 2)), 8
  1376.   NEXT
  1377.  NEXT
  1378.  
  1379.  PAINT (Xmax \ 2 + 35, Ymax \ 2 + 10), 3, 8
  1380.  
  1381.  x$ = CHR$(66) + CHR$(3) + CHR$(&H50) + CHR$(&H50) + CHR$(15) + CHR$(15) + CHR$(3)
  1382.  
  1383.  FOR i = 1 TO 7
  1384.   j = ASC(MID$(x$, i, 1))
  1385.   PAINT (Points(i, 8, 1), Points(i, 8, 2) + 10), j, 8
  1386.  NEXT
  1387.  
  1388.  
  1389. ' calculate the corridor walls for the "Yellow" column
  1390.  
  1391.  x1 = Points(1, 8, 1) + 5
  1392.  y1 = Points(1, 8, 2) + 3
  1393.  x2 = Points(7, 8, 1) + 5
  1394.  y2 = Points(7, 8, 2) + 3
  1395.  LINE (x1, y1)-(x2, y2), 8
  1396.  x1 = Points(1, 8, 1) - 5
  1397.  x2 = Points(7, 8, 1) - 5
  1398.  LINE (x1, y1)-(x2, y2), 8
  1399.  
  1400. ' draw the outer corridor wall for the "Red" and "Blue" columns
  1401.  
  1402.  x1 = Points(1, 16, 1) - 3
  1403.  y1 = Points(1, 16, 2) - 6
  1404.  x2 = Points(7, 16, 1) - 3
  1405.  y2 = Points(7, 16, 2) - 6
  1406.  LINE (x1, y1)-(x2, y2), 8
  1407.  x1 = Points(1, 20, 1) + 2
  1408.  y1 = Points(1, 20, 2) - 4
  1409.  x2 = Points(7, 20, 1) + 1
  1410.  y2 = Points(7, 20, 2) - 6
  1411.  LINE (x1, y1)-(x2, y2), 8
  1412.  
  1413. ' draw the inner corridor wall for the "Red" and "Blue" columns
  1414.  
  1415.  x1 = Points(1, 16, 1) + 7
  1416.  y1 = Points(1, 16, 2)
  1417.  x2 = Points(7, 16, 1) + 7
  1418.  y2 = Points(7, 16, 2)
  1419.  LINE (x1, y1)-(x2, y2), 8
  1420.  
  1421.  x1 = Points(1, 20, 1) - 7
  1422.  y1 = Points(1, 20, 2)
  1423.  x2 = Points(7, 20, 1) - 7
  1424.  y2 = Points(7, 20, 2)
  1425.  LINE (x1, y1)-(x2, y2), 8
  1426.  
  1427. ' shade all the columns grey
  1428.  
  1429.  FOR i = 5 TO 11 STEP 3
  1430.   j = (i \ 2) * 4
  1431.  
  1432.   FOR k = 2 TO 6
  1433.    FOR m = 1 TO 2
  1434.     coord(m) = (Points(k, j, m) + Points(k - 1, j, m)) \ 2
  1435.    NEXT
  1436.    PAINT (coord(1), coord(2)), 7, 8
  1437.   NEXT
  1438.  
  1439.  NEXT
  1440.  
  1441.  fg = 4: CALL ziPublishHere(4, 2, CHR$(24), 0, 0)
  1442.  fg = 0: CALL ziPublish(" columns in", 0, 0)
  1443.  fg = 4: CALL ziPublishHere(5, 2, CHR$(25), 0, 0)
  1444.  fg = 0: CALL ziPublish(" columns out", 0, 0)
  1445.  fg = 4: CALL ziPublishHere(6, 2, "O", 0, 0)
  1446.  fg = 0: CALL ziPublish(" outer ring", 0, 0)
  1447.  fg = 4: CALL ziPublishHere(7, 2, "I", 0, 0)
  1448.  fg = 0: CALL ziPublish(" inner ring", 0, 0)
  1449.  fg = 4: CALL ziPublishHere(9, 2, "Q", 0, 0)
  1450.  fg = 0: CALL ziPublish("uit", 0, 0)
  1451.  fg = 4: CALL ziPublishHere(10, 2, "R", 0, 0)
  1452.  fg = 0: CALL ziPublish("estart", 0, 0)
  1453.  fg = 4: CALL ziPublishHere(11, 2, "S", 0, 0)
  1454.  fg = 0: CALL ziPublish("cramble", 0, 0)
  1455.  fg = 4: CALL ziPublishHere(12, 2, "U", 0, 0)
  1456.  fg = 0: CALL ziPublish("ndo", 0, 0)
  1457.  
  1458.  fg = 4: CALL ziPublishHere(22, 4, "F1 ", 0, 0)
  1459.  fg = 4: CALL ziPublishHere(23, 4, "F2 ", 0, 0)
  1460.  fg = 0: CALL ziPublish("show", 0, 0)
  1461.  
  1462.  IF Anitmated = 0 THEN
  1463.     x$ = " "
  1464.  ELSE
  1465.     x$ = CHR$(251)
  1466.  END IF
  1467.  fg = 1: CALL ziPublishHere(2, 30, x$ + " ", 0, 1)
  1468.  fg = 4: CALL ziPublish("A", 0, 0)
  1469.  fg = 0: CALL ziPublish("nimate", 0, 0)
  1470.  
  1471.  fg = 8: CALL ziPublishHere(4, 34, "count:", 0, 1)
  1472.  x$ = RIGHT$("00000" + MID$(STR$(Count), 2), 6)
  1473.  fg = 0: CALL ziPublishHere(5, 34, x$, 0, 2)
  1474.  
  1475.  GOSUB RecordingBlock
  1476.  
  1477.  
  1478.  GOSUB ReColourBeads
  1479.  RETURN
  1480. '<p>
  1481. '   ╔════════════════╗
  1482. '   ║   SetArrows    ╟─────────────────────────────────────────────┐
  1483. '   ╚╤═══════════════╝                                             │
  1484. '    │  Set the arrows as required                                 │
  1485. '    │                                                             │
  1486. '    └─────────────────────────────────────────────────────────────┘
  1487. SetArrows:
  1488.  
  1489.  fg = 0
  1490.  CALL zsLocateGCursor(191, 105)
  1491.  
  1492.  IF Beads(2, 2) = 0 THEN
  1493.  
  1494.   IF Automatic = 0 THEN
  1495.    CALL ziPublish(CHR$(24), 0, 0)
  1496.   END IF
  1497.  
  1498.   FOR i = 5 TO 11 STEP 3
  1499.    j = (i \ 2) * 4
  1500.  
  1501.    FOR m = 1 TO 2
  1502.     coord(m) = (Points(7, j, m) + Points(6, j, m)) \ 2
  1503.    NEXT
  1504.    IF Automatic = 0 THEN
  1505.     PAINT (coord(1), coord(2)), 7, 8
  1506.     CIRCLE (coord(1), coord(2)), 2, 8
  1507.     PAINT (coord(1), coord(2)), Hue(Beads(7, j \ 4)), 8
  1508.    END IF
  1509.  
  1510.    FOR m = 1 TO 2
  1511.     coord(m) = (Points(2, j, m) + Points(1, j, m)) \ 2
  1512.    NEXT
  1513.    IF Automatic = 0 THEN
  1514.     CIRCLE (coord(1), coord(2)), 2, 0
  1515.     PAINT (Points(2, j, 1), Points(2, j, 2) - 5 * SGN(j - 12)), 66, 8
  1516.    END IF
  1517.   NEXT
  1518.  
  1519.  ELSE
  1520.  
  1521.   IF Automatic = 0 THEN
  1522.    CALL ziPublish(CHR$(25), 0, 0)
  1523.   END IF
  1524.  
  1525.   FOR i = 5 TO 11 STEP 3
  1526.    j = (i \ 2) * 4
  1527.  
  1528.    FOR m = 1 TO 2
  1529.     coord(m) = (Points(2, j, m) + Points(1, j, m)) \ 2
  1530.    NEXT
  1531.    IF Automatic = 0 THEN
  1532.     PAINT (coord(1), coord(2)), 7, 8
  1533.     CIRCLE (coord(1), coord(2)), 2, 8
  1534.     PAINT (coord(1), coord(2)), Hue(Beads(2, j \ 4)), 8
  1535.    END IF
  1536.  
  1537.    FOR m = 1 TO 2
  1538.     coord(m) = (Points(7, j, m) + Points(6, j, m)) \ 2
  1539.    NEXT
  1540.    IF Automatic = 0 THEN
  1541.     CIRCLE (coord(1), coord(2)), 2, 0
  1542.     PAINT (Points(7, j, 1), Points(7, j, 2) - 5 * SGN(j - 12)), 66, 8
  1543.    END IF
  1544.   NEXT
  1545.  
  1546.  END IF
  1547.  RETURN
  1548. '<p>
  1549. '   ╔═════════════════════╗
  1550. '   ║    StartScreen      ╟────────────────────────────────────────┐
  1551. '   ╚╤════════════════════╝                                        │
  1552. '    │   Start the screen - with the KHAMESH logo - based on       │
  1553. '    │   the colour noted in "bg"                                  │
  1554. '    │                                                             │
  1555. '    └─────────────────────────────────────────────────────────────┘
  1556. StartScreen:
  1557.  
  1558.  fg = 7
  1559.  LINE (0, 0)-(Xmax, Ymax), bg, BF
  1560.  fg = 4: CALL ziPublishHere(2, 2, "KHAMESH", 2, 0)
  1561.  
  1562.  RETURN
  1563. '<p>
  1564. '   ╔═══════════════════╗
  1565. '   ║    UpDownArrow    ╟──────────────────────────────────────────┐
  1566. '   ╚╤══════════════════╝                                          │
  1567. '    │   Move beads to new configuration when shuttling the        │
  1568. '    │   columns (with "*", UParrow and DNarrow)                   │
  1569. '    │                                                             │
  1570. '    └─────────────────────────────────────────────────────────────┘
  1571. UpDownArrow:
  1572.  
  1573.  FOR i = 5 TO 11 STEP 3
  1574.   j = (i \ 2) * 4
  1575.   IF Beads(2, 5) = 0 THEN
  1576.    FOR k = 2 TO 7
  1577.     Beads(k, j \ 4) = Beads(k + 1, j \ 4)
  1578.     FOR m = 1 TO 2
  1579.      coord(m) = (Points(k, j, m) + Points(k - 1, j, m)) \ 2
  1580.     NEXT
  1581.     IF Automatic = 0 THEN
  1582.      PAINT (coord(1), coord(2)), Hue(Beads(k, j \ 4)), 8
  1583.     END IF
  1584.    NEXT
  1585.   ELSE
  1586.    FOR k = 7 TO 2 STEP -1
  1587.     Beads(k, j \ 4) = Beads(k - 1, j \ 4)
  1588.     FOR m = 1 TO 2
  1589.      coord(m) = (Points(k, j, m) + Points(k - 1, j, m)) \ 2
  1590.     NEXT
  1591.     IF Automatic = 0 THEN
  1592.      PAINT (coord(1), coord(2)), Hue(Beads(k, j \ 4)), 8
  1593.     END IF
  1594.    NEXT
  1595.   END IF
  1596.  NEXT
  1597.  GOSUB SetArrows
  1598.  
  1599.  IF Automatic = 0 THEN
  1600.   IF Animated = 1 THEN
  1601.    PLAY "MBL64N0N0"
  1602.    DO: LOOP UNTIL PLAY(0) = 0
  1603.   END IF
  1604.  END IF
  1605.  
  1606.  RETURN
  1607. '<p>
  1608. '   ╔═══════════════════╗
  1609. '   ║    WhatMacros     ╟──────────────────────────────────────────┐
  1610. '   ╚╤══════════════════╝                                          │
  1611. '    │   Go through records in KHAMESH.MAC to determine the        │
  1612. '    │   existing macros                                           │
  1613. '    │                                                             │
  1614. '    └─────────────────────────────────────────────────────────────┘
  1615. WhatMacros:
  1616.  
  1617.  FOR i = 1 TO 26
  1618.  
  1619.   GET #1, i, FullRecord
  1620.   SELECT CASE ASC(FullRecord.MacroLetter)
  1621.   CASE i + 64
  1622.    Alpha(i) = 1  'macro
  1623.   CASE i + 96
  1624.    Alpha(i) = 2  'function
  1625.   END SELECT
  1626.  
  1627.  NEXT
  1628.  
  1629.  GOSUB Alphabet
  1630.  
  1631.  RETURN
  1632. '<p>
  1633. '   ╔═══════════════════╗
  1634. '   ║    WhichMacro     ╟──────────────────────────────────────────┐
  1635. '   ╚╤══════════════════╝                                          │
  1636. '    │   Publish box calling for "Which Macro?"                    │
  1637. '    │                                                             │
  1638. '    └─────────────────────────────────────────────────────────────┘
  1639. WhichMacro:
  1640.  
  1641.  bg = 48
  1642.  x = Xmax \ 6: y = Ymax \ 4
  1643.  LINE (x, y)-(5 * x, y + y), bg, BF
  1644.  LINE (x, y)-(5 * x, y + y), 0, B
  1645.  fg = 4
  1646.  CALL ziPublishHere(10, 9, "Which Macro?", 2, 0)
  1647.  
  1648.  RETURN
  1649.  
  1650. '<->
  1651. '<p>
  1652. '++++++++++++++++++++++++
  1653. SUB ziDragging
  1654.  
  1655.   IF Mouse AND MCursorVis THEN
  1656.     SELECT CASE Response
  1657.     CASE 2052 TO 2054
  1658.       Regs.AX = 3
  1659.       CALL zzBasicInt(&H33)
  1660.       IF Regs.BX = Response - 2051 THEN
  1661.     EXIT SUB
  1662.       END IF
  1663.     END SELECT
  1664.   END IF
  1665.   CALL ziExhaust
  1666.  
  1667. END SUB
  1668.  
  1669. '<p>
  1670. '++++++++++++++++++++++++
  1671. SUB ziDrawBank (FromButton, ToButton)
  1672.  
  1673.   CALL ziSetMCursorVis(10)
  1674.  
  1675.   FOR i = FromButton TO ToButton
  1676.  
  1677.     IF Bank(i).Active THEN
  1678.  
  1679.       IF Bank(i).State THEN
  1680.     colour1 = 8
  1681.       ELSE
  1682.     colour1 = 15
  1683.       END IF
  1684.       colour2 = colour1 XOR 7
  1685.  
  1686.       XCoord = Bank(i).Xloc
  1687.       YCoord = Bank(i).Yloc
  1688.       XWidth = Bank(i).Wide
  1689.       YDepth = Bank(i).Deep
  1690.       X2Coord = XCoord + XWidth
  1691.  
  1692.       IF YDepth THEN
  1693.     IF YDepth = 1 THEN
  1694.       Y2Coord = YCoord + XWidth / XYratio!
  1695.     ELSE
  1696.       Y2Coord = YCoord + YDepth
  1697.     END IF
  1698.     LINE (XCoord, YCoord)-(X2Coord - 1, YCoord), colour1
  1699.     LINE (XCoord, YCoord)-(XCoord, Y2Coord - 1), colour1
  1700.     LINE (XCoord + 1, Y2Coord)-(X2Coord, Y2Coord), colour2
  1701.     LINE (X2Coord, YCoord)-(X2Coord, Y2Coord), colour2
  1702.       ELSE
  1703.     A = XWidth \ 2
  1704.     B = A / XYratio!
  1705.     C = XCoord + A
  1706.     D = YCoord + B
  1707.  
  1708.     LINE (XCoord, YCoord)-(C + A, D + B), 7, BF
  1709.  
  1710.     CIRCLE (C, D), A, 8
  1711.     CIRCLE (C, D), A - 1, 8
  1712.     PAINT (C, D), 7, 7
  1713.     IF Bank(i).State THEN
  1714.       CIRCLE (C, D), XWidth \ 3, 8
  1715.       PAINT (C, D), 8, 8
  1716.     END IF
  1717.       END IF
  1718.     END IF
  1719.  
  1720.   NEXT
  1721.  
  1722.   CALL ziSetMCursorVis(11)
  1723.  
  1724. END SUB
  1725.  
  1726. '<p>
  1727. '++++++++++++++++++++++++
  1728. SUB ziExhaust
  1729.  
  1730.   DO
  1731.     x$ = INKEY$
  1732.   LOOP WHILE LEN(x$)
  1733.  
  1734.   IF Mouse AND MCursorVis THEN
  1735.     DO
  1736.       Regs.AX = 3
  1737.       CALL zzBasicInt(&H33)
  1738.     LOOP WHILE (Regs.BX AND 3)
  1739.   END IF
  1740.   Response = 0
  1741. END SUB
  1742.  
  1743. '<p>
  1744. '++++++++++++++++++++++++
  1745. SUB ziLoadFont (Font$)
  1746.  
  1747.   DEF SEG = VARSEG(Font(0, 0))
  1748.  
  1749.   Module$ = Font$ + ".OVL"
  1750.   CALL zzInPath(Module$)
  1751.   IF Module$ = "" THEN
  1752.     Module$ = Font$ + ".OVL"
  1753.     ERROR 255
  1754.   ELSE
  1755.     BLOAD Module$, VARPTR(Font(0, 0))
  1756.   END IF
  1757.  
  1758.   DEF SEG
  1759.  
  1760. END SUB
  1761.  
  1762. '<p>
  1763. '++++++++++++++++++++++++
  1764. SUB ziLocateMCursor (XCoord, YCoord)
  1765.  
  1766.   IF Mouse THEN
  1767.     MXloc = XCoord
  1768.     MYloc = YCoord
  1769.     Regs.AX = 4
  1770.     Regs.CX = XCoord
  1771.     Regs.DX = YCoord
  1772.     CALL zzBasicInt(&H33)
  1773.     CALL ziSetMCursorVis(1)
  1774.   END IF
  1775.  
  1776. END SUB
  1777.  
  1778. '<p>
  1779. '++++++++++++++++++++++++
  1780. SUB ziMouseOnButton (FromButton, ToButton)
  1781.  
  1782.   FoundButton = 0
  1783.   FOR i = FromButton TO ToButton
  1784.     IF Bank(i).Active THEN
  1785.       IF Bank(i).Deep < 2 THEN
  1786.     j = Bank(i).Wide / XYratio!
  1787.       ELSE
  1788.     j = Bank(i).Deep
  1789.       END IF
  1790.       IF MXloc > Bank(i).Xloc THEN
  1791.     IF MXloc < Bank(i).Xloc + Bank(i).Wide THEN
  1792.       IF MYloc > Bank(i).Yloc THEN
  1793.         IF MYloc < Bank(i).Yloc + j THEN
  1794.           FoundButton = i
  1795.           EXIT SUB
  1796.         END IF
  1797.       END IF
  1798.     END IF
  1799.       END IF
  1800.     ELSE
  1801.       EXIT SUB
  1802.     END IF
  1803.   NEXT
  1804.  
  1805. END SUB
  1806.  
  1807. '<p>
  1808. '++++++++++++++++++++++++
  1809. SUB ziPublish (Printstring$, size, italic)
  1810.  
  1811.   CALL ziSetMCursorVis(10)
  1812.  
  1813.   xx = POINT(0)
  1814.   yy = POINT(1)
  1815.   IF size THEN
  1816.     Scale = size
  1817.   ELSE
  1818.     Scale = 1
  1819.   END IF
  1820.  
  1821.   LenString = LEN(Printstring$)
  1822.  
  1823.   ExpScale = 8 * Scale
  1824.   limxx = xx + ExpScale * LenString - 1
  1825.   limyy = yy + ExpScale - 1
  1826.  
  1827.   IF italic AND 1 THEN
  1828.     limxx = limxx + 4 * Scale
  1829.   END IF
  1830.  
  1831.  
  1832.   IF italic AND 2 THEN
  1833.   ELSE
  1834.     LINE (xx, yy)-(limxx, limyy), bg, BF
  1835.   END IF
  1836.  
  1837.  
  1838.   FOR A = 0 TO LenString - 1
  1839.     x = ASC(MID$(Printstring$, A + 1, 1))
  1840.     B = xx + ExpScale * A
  1841.     FOR y = 0 TO 7
  1842.       C = Font(x, y)
  1843.       D = y * Scale
  1844.       e = yy + D
  1845.       IF italic AND 1 THEN
  1846.     F = B + 4 * Scale - (D + Scale - 1) \ 2 - 1
  1847.       ELSE
  1848.     F = B
  1849.       END IF
  1850.       G = 128
  1851.       DO
  1852.     IF C AND G THEN
  1853.       FOR h = 0 TO Scale - 1
  1854.         FOR i = 0 TO Scale - 1
  1855.           PSET (F + h, e + i), fg
  1856.         NEXT
  1857.       NEXT
  1858.     END IF
  1859.     F = F + Scale
  1860.     G = G \ 2
  1861.       LOOP UNTIL G = 0
  1862.     NEXT
  1863.   NEXT
  1864.   CALL zsLocateGCursor(limxx + 1, yy)
  1865.  
  1866.   CALL ziSetMCursorVis(11)
  1867.  
  1868. END SUB
  1869.  
  1870. SUB ziPublishHere (row, col, Printstring$, size, italic)
  1871.  
  1872.  IF row + col > 0 THEN
  1873.   LOCATE row, col
  1874.  END IF
  1875.  CALL zsAlignGCursor
  1876.  CALL ziPublish(Printstring$, size, italic)
  1877.  CALL zsAlignTCursor
  1878.  
  1879. END SUB
  1880.  
  1881. '<p>
  1882. '++++++++++++++++++++++++
  1883. SUB ziRadio (Button, FromButton, ToButton)
  1884.  
  1885.   IF Button >= FromButton THEN
  1886.     IF Button <= ToButton THEN
  1887.       FOR A = FromButton TO ToButton
  1888.     Bank(A).State = 0
  1889.       NEXT
  1890.     END IF
  1891.   END IF
  1892.  
  1893.   Bank(Button).State = 1
  1894.   CALL ziDrawBank(FromButton, ToButton)
  1895.  
  1896. END SUB
  1897.  
  1898. '<p>
  1899. '++++++++++++++++++++++++
  1900. SUB ziReadField (Min, Max, Permitted$)
  1901.  
  1902.   CALL ziSetMCursorVis(10)
  1903.  
  1904.   atRow = CSRLIN
  1905.   atCol = POS(x)
  1906.   Field$ = ""
  1907.   PRINT CHR$(219); SPACE$(Max);
  1908.   Rules$ = UCASE$(Permitted$)
  1909.  
  1910.   brake = 1
  1911.   WHILE brake
  1912.     x$ = ""
  1913.     WHILE LEN(x$) = 0
  1914.       x$ = INKEY$
  1915.     WEND
  1916.     IF INSTR(Rules$, "C") THEN x$ = UCASE$(x$)
  1917.     oldLen = LEN(Field$)
  1918.     Good = 0
  1919.     IF INSTR(Rules$, ".") THEN
  1920.       IF x$ = "." THEN
  1921.     IF INSTR(Field$, ".") = 0 THEN
  1922.       Good = 1
  1923.     END IF
  1924.       END IF
  1925.     END IF
  1926.     IF INSTR(Rules$, "N") THEN
  1927.       IF INSTR("0123456789", x$) THEN
  1928.     Good = 1
  1929.       END IF
  1930.     END IF
  1931.     IF INSTR(Rules$, "S") THEN
  1932.       IF x$ = " " THEN
  1933.     Good = 1
  1934.       END IF
  1935.     END IF
  1936.     IF INSTR(Rules$, "X") THEN
  1937.       IF INSTR("ABCDEFGHIJKLMNOPQRSTUVWXYZ", UCASE$(x$)) THEN
  1938.     Good = 1
  1939.       END IF
  1940.     END IF
  1941.     IF INSTR(Rules$, "Y") THEN
  1942.       IF INSTR("YyNy", x$) THEN
  1943.     Good = 1
  1944.       END IF
  1945.     END IF
  1946.     IF Good THEN
  1947.       Field$ = Field$ + x$
  1948.       IF INSTR(Field$, ".") THEN
  1949.     NewMax = Max + 1
  1950.       ELSE
  1951.     NewMax = Max
  1952.       END IF
  1953.       Field$ = MID$(Field$, 1, NewMax)
  1954.     END IF
  1955.  
  1956.     ' handle Bkspace
  1957.     IF ASC(x$) = 8 AND LEN(Field$) THEN
  1958.       Field$ = MID$(Field$, 1, LEN(Field$) - 1)
  1959.     END IF
  1960.  
  1961.     Signif$ = Field$ + "X"
  1962.     WHILE INSTR(" 0", MID$(Signif$, 1, 1))
  1963.       Signif$ = MID$(Signif$, 2)
  1964.     WEND
  1965.     IF INSTR(Signif$, ".") THEN
  1966.       SignifLen = LEN(Signif$) - 2
  1967.     ELSE
  1968.       SignifLen = LEN(Signif$) - 1
  1969.     END IF
  1970.  
  1971.     ' handle Enter
  1972.     IF ASC(x$) = 13 AND SignifLen >= Min THEN
  1973.       oldLen = LEN(Field$) + 1
  1974.       brake = 0
  1975.     END IF
  1976.  
  1977.     ' handle Esc
  1978.     IF ASC(x$) = 27 THEN
  1979.       LOCATE atRow, atCol
  1980.       PRINT CHR$(219); SPACE$(Max);
  1981.       Field$ = ""
  1982.       IF INSTR(Rules$, "E") THEN
  1983.     EXIT SUB
  1984.       END IF
  1985.     END IF
  1986.  
  1987.     ' reprint if change, or beep if no change
  1988.     IF oldLen = LEN(Field$) THEN
  1989.       BEEP
  1990.     ELSE
  1991.       LOCATE atRow, atCol
  1992.       IF INSTR(Rules$, "P") THEN
  1993.     PRINT STRING$(LEN(Field$), 254); CHR$(219); " ";
  1994.       ELSE
  1995.     PRINT Field$; CHR$(219); " ";
  1996.       END IF
  1997.     END IF
  1998.  
  1999.     ' check for auto-Enter
  2000.     IF INSTR(Rules$, "A") THEN
  2001.       IF SignifLen = Max THEN
  2002.     brake = 0
  2003.       END IF
  2004.     END IF
  2005.   WEND
  2006.  
  2007.   ' justify if required
  2008.   IF INSTR(Rules$, "J") THEN
  2009.     WHILE MID$(Field$, 1, 1) = "0"
  2010.       Field$ = MID$(Field$, 2)
  2011.     WEND
  2012.     Field$ = RIGHT$(SPACE$(NewMax) + Field$, NewMax)
  2013.   END IF
  2014.  
  2015.   ' reprint, deleting the cursor
  2016.   LOCATE atRow, atCol
  2017.   IF INSTR(Rules$, "P") THEN
  2018.     PRINT STRING$(LEN(Field$), 254); " ";
  2019.   ELSE
  2020.     PRINT Field$; " ";
  2021.   END IF
  2022.  
  2023.   CALL ziSetMCursorVis(11)
  2024.  
  2025. END SUB
  2026.  
  2027. '<p>
  2028. '++++++++++++++++++++++++
  2029. SUB ziSetMCursorVis (Status) STATIC
  2030.  
  2031.   IF Mouse THEN
  2032.     SELECT CASE Status
  2033.     CASE 0
  2034.       IF MCursorVis THEN
  2035.        Regs.AX = 2
  2036.        CALL zzBasicInt(&H33)
  2037.       END IF
  2038.     CASE 1
  2039.       Regs.AX = 1
  2040.       CALL zzBasicInt(&H33)
  2041.     CASE 10
  2042.       Regs.AX = &H2A
  2043.       CALL zzBasicInt(&H33)
  2044.       IF Regs.AX = 0 THEN
  2045.     TempFlag = 1
  2046.     Regs.AX = 2
  2047.     CALL zzBasicInt(&H33)
  2048.       ELSE
  2049.     TempFlag = 0
  2050.       END IF
  2051.     CASE 11
  2052.       IF TempFlag THEN
  2053.     Regs.AX = 1
  2054.     CALL zzBasicInt(&H33)
  2055.       END IF
  2056.     END SELECT
  2057.     Regs.AX = &H2A
  2058.     CALL zzBasicInt(&H33)
  2059.     IF Regs.AX = 0 THEN
  2060.       MCursorVis = 1
  2061.     ELSE
  2062.       MCursorVis = 0
  2063.     END IF
  2064.   END IF
  2065. END SUB
  2066.  
  2067. '<p>
  2068. '++++++++++++++++++++++++
  2069. SUB ziWander (Timeout!)
  2070.  
  2071.   IF Timeout! = 0 THEN
  2072.     WatchFor! = TIMER + 3600
  2073.   ELSE
  2074.     WatchFor! = TIMER + Timeout!
  2075.   END IF
  2076.  
  2077.   Response = 0
  2078.  
  2079.   DO
  2080.     x$ = INKEY$
  2081.     IF LEN(x$) THEN
  2082.       SELECT CASE LEN(x$)
  2083.       CASE 1
  2084.     A = INSTR(Allowed$, x$)
  2085.     IF A THEN
  2086.       Response = A
  2087.       EXIT DO
  2088.     END IF
  2089.     SELECT CASE ASC(x$)
  2090.     CASE 8: Response = 261
  2091.     CASE 9: Response = 266
  2092.     CASE 10: Response = 512
  2093.     CASE 13: Response = 256
  2094.     CASE 27: Response = 267
  2095.     CASE 127: Response = 517
  2096.     END SELECT
  2097.     IF Response THEN
  2098.       EXIT DO
  2099.     END IF
  2100.       CASE 2
  2101.     Rightmost = ASC(RIGHT$(x$, 1))
  2102.     SELECT CASE Rightmost
  2103.     CASE 15: Response = 1019
  2104.     CASE 59 TO 68
  2105.       Response = 4038
  2106.     CASE 72: Response = 187
  2107.     CASE 71 TO 73
  2108.       Response = 191
  2109.     CASE 75: Response = 182
  2110.     CASE 77: Response = 181
  2111.     CASE 80: Response = 180
  2112.     CASE 79 TO 81
  2113.       Response = 184
  2114.     CASE 84 TO 93
  2115.       Response = 16301
  2116.     CASE 94 TO 103
  2117.       Response = 8099
  2118.     CASE 115 TO 116
  2119.       Response = 398
  2120.     CASE 117: Response = 402
  2121.     CASE 118: Response = 403
  2122.     CASE 119: Response = 399
  2123.     CASE 127: Response = 390
  2124.     CASE 132: Response = 388
  2125.     CASE 133 TO 134
  2126.       Response = 3974
  2127.     CASE 135 TO 136
  2128.       Response = 16260
  2129.     CASE 137 TO 138
  2130.       Response = 8066
  2131.     END SELECT
  2132.     IF Response THEN
  2133.       Response = Response + Rightmost
  2134.       EXIT DO
  2135.     END IF
  2136.       END SELECT
  2137.     END IF
  2138.  
  2139.     IF Mouse AND MCursorVis THEN
  2140.       Regs.AX = 3
  2141.       CALL zzBasicInt(&H33)
  2142.       SELECT CASE Regs.BX
  2143.       CASE 1 TO 3
  2144.     Response = 2048 + Regs.BX
  2145.     nowtime! = TIMER
  2146.     DO
  2147.       Regs.AX = 3
  2148.       CALL zzBasicInt(&H33)
  2149.       IF Regs.BX = 0 THEN EXIT DO
  2150.     LOOP UNTIL TIMER - nowtime! > .3
  2151.     IF Regs.BX = Response - 2048 THEN
  2152.       Response = Response + 3
  2153.     ELSE
  2154.       IF Regs.BX = 0 AND Response = 2049 AND DClick THEN
  2155.         nowtime! = TIMER
  2156.         DO
  2157.           Regs.AX = 3
  2158.           CALL zzBasicInt(&H33)
  2159.           IF Regs.BX = 1 THEN EXIT DO
  2160.         LOOP UNTIL TIMER - nowtime! > .3
  2161.         IF Regs.BX = 1 THEN
  2162.           Response = 2048
  2163.           CALL ziExhaust
  2164.         END IF
  2165.       END IF
  2166.       IF Regs.BX = 3 THEN
  2167.         Response = 2051
  2168.       END IF
  2169.     END IF
  2170.       END SELECT
  2171.       IF Response THEN
  2172.     MXloc = Regs.CX
  2173.     MYloc = Regs.DX
  2174.     EXIT DO
  2175.       END IF
  2176.     END IF
  2177.  
  2178.   LOOP UNTIL WatchFor! < TIMER
  2179.   HResponse = Response \ 256
  2180.   LResponse = Response MOD 256
  2181.  
  2182. END SUB
  2183.  
  2184. '<p>
  2185. '++++++++++++++++++++++++
  2186. SUB zsAlignGCursor
  2187.  
  2188.   row = CSRLIN
  2189.   col = POS(0)
  2190.   GXloc = (col - 1) * ((Xmax + 1) \ Cols)
  2191.   GYloc = (row - 1) * ((((Ymax + 1) \ Rows) * Rows + 1) \ Rows)
  2192.   CALL zsLocateGCursor(GXloc, GYloc)
  2193.  
  2194. END SUB
  2195.  
  2196. '<p>
  2197. '++++++++++++++++++++++++
  2198. SUB zsAlignTCursor
  2199.  
  2200.   GXloc = POINT(0)
  2201.   GYloc = POINT(1)
  2202.   A = (Xmax + 1) / Cols
  2203.   B = (Ymax + 1) / Rows
  2204.   col = (GXloc + A - 1) \ A + 1
  2205.   row = (GYloc + B - 1) \ B + 1
  2206.   LOCATE row, col
  2207.   CALL zsAlignGCursor
  2208.  
  2209. END SUB
  2210.  
  2211. '<p>
  2212. '++++++++++++++++++++++++
  2213. SUB zsLocateGCursor (XCoord, YCoord)
  2214.  
  2215.   GXloc = XCoord
  2216.   GYloc = YCoord
  2217.   PSET (GXloc, GYloc), POINT(GXloc, GYloc)
  2218.  
  2219. END SUB
  2220.  
  2221. '<p>
  2222. '++++++++++++++++++++++++
  2223. SUB zsPastel (XCoord, YCoord, Wide, Deep, colour1, colour2)
  2224.  
  2225.   CALL ziSetMCursorVis(10)
  2226.  
  2227.   IF Deep < 2 THEN
  2228.     A = Wide / XYratio!
  2229.   ELSE
  2230.     A = Deep
  2231.   END IF
  2232.  
  2233.   LINE (XCoord, YCoord)-(XCoord + Wide - 1, YCoord + A - 1), colour1, BF
  2234.   FOR B = XCoord TO XCoord + Wide - 1 STEP 2
  2235.     LINE (B, YCoord)-(B, YCoord + A - 1), colour2, , &H5555
  2236.   NEXT
  2237.   FOR B = XCoord + 1 TO XCoord + Wide - 1 STEP 2
  2238.     LINE (B, YCoord)-(B, YCoord + A - 1), colour2, , &HAAAA
  2239.   NEXT
  2240.  
  2241.   CALL ziSetMCursorVis(11)
  2242.  
  2243. END SUB
  2244.  
  2245. '<p>
  2246. '++++++++++++++++++++++++
  2247. SUB zsSetScrnMode (Mode, HiRows, HiCols)
  2248.  
  2249.   CALL ziSetMCursorVis(10)
  2250.  
  2251.   ScrnMode = Mode
  2252.   SELECT CASE Mode
  2253.   CASE 9
  2254.     SCREEN 9
  2255.     IF HiRows THEN
  2256.       Rows = 43
  2257.     ELSE
  2258.       Rows = 25
  2259.     END IF
  2260.     Xmax = 639
  2261.     Ymax = 349
  2262.   CASE 12
  2263.     SCREEN 12
  2264.     IF HiRows THEN
  2265.       Rows = 60
  2266.     ELSE
  2267.       Rows = 30
  2268.     END IF
  2269.     Xmax = 639
  2270.     Ymax = 479
  2271.   CASE 13
  2272.     SCREEN 13
  2273.     Rows = 25
  2274.     Cols = 40
  2275.     Xmax = 319
  2276.     Ymax = 199
  2277.   CASE ELSE
  2278.     RETURN
  2279.   END SELECT
  2280.  
  2281.   IF Mode <> 13 THEN
  2282.     IF HiCols THEN
  2283.       Cols = 80
  2284.     ELSE
  2285.       Cols = 40
  2286.     END IF
  2287.   END IF
  2288.   WIDTH Cols, Rows
  2289.   CLS
  2290.   SELECT CASE Mode
  2291.   CASE 9
  2292.     COLOR fg, 0
  2293.   CASE ELSE
  2294.     COLOR fg
  2295.   END SELECT
  2296.  
  2297.   LINE (0, 0)-(Xmax, Ymax), bg, BF
  2298.   LOCATE 1, 1, 0
  2299.   PSET (0, 0), bg
  2300.   XYratio! = .75 * (Xmax + 1) / (Ymax + 1)
  2301.  
  2302.   CALL ziSetMCursorVis(11)
  2303.  
  2304. END SUB
  2305.  
  2306. '<p>
  2307. '++++++++++++++++++++++++
  2308. SUB zsSubstitute (XCoord, YCoord, Wide, Deep, colour1, colour2)
  2309.  
  2310.   CALL ziSetMCursorVis(10)
  2311.  
  2312.   IF Deep < 2 THEN
  2313.     A = Wide / XYratio!
  2314.   ELSE
  2315.     A = Deep
  2316.   END IF
  2317.   FOR B = XCoord TO XCoord + Wide - 1
  2318.     FOR C = YCoord TO YCoord + A - 1
  2319.       IF POINT(B, C) = colour1 THEN
  2320.     PSET (B, C), colour2
  2321.       END IF
  2322.     NEXT
  2323.   NEXT
  2324.  
  2325.   CALL ziSetMCursorVis(11)
  2326.  
  2327. END SUB
  2328.  
  2329. '<p>
  2330. '++++++++++++++++++++++++
  2331. SUB zzAlphaSort (SortData$())
  2332.  
  2333.  DIM SortPointers(SortCount, 2)
  2334.  
  2335.  FOR i = 2 TO SortCount
  2336.   j = 1
  2337.  
  2338.   DO
  2339.    k = j
  2340.    IF SortData$(i) < SortData$(j) THEN
  2341.     j = SortPointers(j, 1)
  2342.    ELSE
  2343.     j = SortPointers(j, 2)
  2344.    END IF
  2345.   LOOP WHILE j <> 0
  2346.  
  2347.   IF SortData$(i) < SortData$(k) THEN
  2348.    SortPointers(k, 1) = i
  2349.   ELSE
  2350.    SortPointers(k, 2) = i
  2351.   END IF
  2352.  NEXT
  2353.  
  2354.  SortPointers(0, 1) = 1
  2355.  
  2356.  
  2357.  FOR i = 1 TO SortCount
  2358.   j = 0
  2359.   DO WHILE SortPointers(j, 1) <> 0
  2360.    k = j
  2361.    j = SortPointers(j, 1)
  2362.   LOOP
  2363.   SortPointers(k, 1) = SortPointers(j, 2)
  2364.  
  2365.   SWAP SortData$(i), SortData$(j)
  2366.   SWAP SortPointers(i, 1), SortPointers(j, 1)
  2367.   SWAP SortPointers(i, 2), SortPointers(j, 2)
  2368.  
  2369.   FOR k = 0 TO SortCount
  2370.    FOR l = 1 TO 2
  2371.     IF SortPointers(k, l) = i THEN SortPointers(k, l) = j
  2372.    NEXT
  2373.   NEXT
  2374.  NEXT
  2375.  
  2376. END SUB
  2377.  
  2378. '<p>
  2379. '++++++++++++++++++++++++
  2380. SUB zzBasicInt (IntType) STATIC
  2381.  
  2382.   DIM ASM(54)
  2383.   DEF SEG = VARSEG(ASM(0))
  2384.  
  2385.   IF ASM(1) = 0 THEN
  2386.     Module$ = "BASICINT.OVL"
  2387.     CALL zzInPath(Module$)
  2388.     IF Module$ = "" THEN
  2389.       Module$ = "BASICINT.OVL"
  2390.       ERROR 255
  2391.     ELSE
  2392.       BLOAD Module$, VARPTR(ASM(0))
  2393.     END IF
  2394.   END IF
  2395.  
  2396.   CALL ABSOLUTE(Regs, IntType, VARPTR(ASM(0)))
  2397.  
  2398.   DEF SEG
  2399.  
  2400. END SUB
  2401.  
  2402. '<p>
  2403. '++++++++++++++++++++++++
  2404. SUB zzChangeDir (Directory$)
  2405.  DIM str AS STRING * 65
  2406.  
  2407.  str = LTRIM$(RTRIM$(UCASE$(Directory$))) + CHR$(0)
  2408.  IF MID$(str, 2, 1) = ":" THEN
  2409.   curdrive$ = MID$(str, 1, 1)
  2410.   str = MID$(str, 3)
  2411.  ELSE
  2412.   Regs.AX = &H1900
  2413.   CALL zzBasicInt(&H21)
  2414.   curdrive$ = CHR$(65 + (Regs.AX AND 255))
  2415.  END IF
  2416.  IF MID$(str, 1, 1) = CHR$(0) THEN
  2417.   GOSUB zzChangeDirAA
  2418.   EXIT SUB
  2419.  END IF
  2420.  str = curdrive$ + ":" + str
  2421.  Regs.AX = &H3B00
  2422.  Regs.DS = VARSEG(str)
  2423.  Regs.DX = VARPTR(str)
  2424.  CALL zzBasicInt(&H21)
  2425.  IF (Regs.FL AND 256) = 256 THEN
  2426.   Directory$ = ""
  2427.  ELSE
  2428.   GOSUB zzChangeDirAA
  2429.  END IF
  2430.  EXIT SUB
  2431.  
  2432. zzChangeDirAA:
  2433.   Regs.AX = &H4700
  2434.   Regs.DX = ASC(curdrive$) - 64
  2435.   Regs.DS = VARSEG(str)
  2436.   Regs.SI = VARPTR(str)
  2437.   CALL zzBasicInt(&H21)
  2438.   i = INSTR(str, CHR$(0))
  2439.   Directory$ = curdrive$ + ":\" + MID$(str, 1, i - 1)
  2440.   RETURN
  2441. END SUB
  2442.  
  2443. '<p>
  2444. '++++++++++++++++++++++++
  2445. SUB zzChangeDrive (Drive$)
  2446.  
  2447.  CALL zzCritOff
  2448.  GOSUB zzChangeDriveProcess
  2449.  CALL zzCritOn
  2450.  
  2451.  EXIT SUB
  2452.  
  2453. zzChangeDriveProcess:
  2454.  
  2455.  Drive$ = LTRIM$(RTRIM$(UCASE$(Drive$)))
  2456.  IF LEN(Drive$) = 0 THEN
  2457.   Regs.AX = &H1900
  2458.   CALL zzBasicInt(&H21)
  2459.   Drive$ = CHR$(65 + (Regs.AX AND 255)) + ":"
  2460.   RETURN
  2461.  END IF
  2462.  
  2463.  IF LEN(Drive$) = 1 THEN Drive$ = Drive$ + ":"
  2464.  IF LEN(Drive$) > 2 THEN Drive$ = "?"
  2465.  
  2466.  IF MID$(Drive$, 2, 1) = ":" THEN
  2467.   drv = ASC(Drive$)
  2468.   Drive$ = "?"
  2469.   IF drv < 65 THEN RETURN
  2470.   IF drv > 90 THEN RETURN
  2471.   drv = drv - 65
  2472.  
  2473. ' establish whether this is a shared drive
  2474.  
  2475.   Regs.AX = &H440E
  2476.   Regs.BX = drv + 1
  2477.   CALL zzBasicInt(&H21)
  2478.   IF (Regs.FL AND 256) = 256 THEN
  2479.    Regs.AX = 0
  2480.   END IF
  2481.   Regs.AX = Regs.AX AND 255
  2482.   IF Regs.AX <> 0 THEN
  2483.    IF Regs.AX <> drv + 1 THEN
  2484.     drv = Regs.AX - 1
  2485.    END IF
  2486.   END IF
  2487.  
  2488. ' establish whether this is a valid drive
  2489.  
  2490.   Regs.AX = &H1C00
  2491.   Regs.DX = drv + 1
  2492.   CALL zzBasicInt(&H21)
  2493.   IF (Regs.AX AND 255) = 255 THEN RETURN
  2494.  
  2495. ' now change to it
  2496.  
  2497.   Regs.AX = &HE00
  2498.   Regs.DX = drv
  2499.   CALL zzBasicInt(&H21)
  2500.  
  2501.   Drive$ = CHR$(65 + drv) + ":"
  2502.  
  2503.  
  2504.  ELSE
  2505.   Drive$ = "?"
  2506.  END IF
  2507.  RETURN
  2508.  
  2509. END SUB
  2510.  
  2511. SUB zzCritOff
  2512.  
  2513.  Regs.AX = &H2524
  2514.  Regs.DS = VARSEG(IRET)
  2515.  Regs.DX = VARPTR(IRET)
  2516.  CALL zzBasicInt(&H21)
  2517.  CritCount = CritCount + 1
  2518.  
  2519. END SUB
  2520.  
  2521. SUB zzCritOn
  2522.  
  2523.  CritCount = CritCount - 1
  2524.  IF CritCount = 0 THEN
  2525.   Regs.AX = &H2524
  2526.   Regs.DS = CritSeg
  2527.   Regs.DX = CritPtr
  2528.   CALL zzBasicInt(&H21)
  2529.  END IF
  2530.  
  2531. END SUB
  2532.  
  2533. '<p>
  2534. '++++++++++++++++++++++++
  2535. SUB zzFileSelectBox (Pattern$)
  2536.  
  2537. DIM Devices(26)  ';valid devices have a non-zero value
  2538. DIM validDevs(27)
  2539.  
  2540. DIM parts$(11) ';ten deep is allowed
  2541. DIM Dirs$(200) ';lots of subdirectories
  2542. DIM Files$(200) ';lots of files
  2543. DIM str AS STRING * 65
  2544.  
  2545.  CALL zzCritOff
  2546.  GOSUB zzFileSelectBoxProcess
  2547.  CALL zzCritOn
  2548.  
  2549.  EXIT SUB
  2550.  
  2551. zzFileSelectBoxProcess:
  2552.  
  2553. ' create the screen
  2554.  
  2555.   IF screendone = 0 THEN
  2556.    bg = 7: fg = 15
  2557.    CALL zsSetScrnMode(9, 1, 1)
  2558.    fg = 0
  2559.    CALL ziPublishHere(3, 34, "Select a File", 1, 3)
  2560.    Stuff$ = "(Please Wait)"
  2561.    fg = 14
  2562.    GOSUB zzFileSelectBoxDD
  2563.  
  2564. ' print the headers
  2565.  
  2566.    fg = 8
  2567.    CALL ziPublishHere(42, 17, "Use left & right arrow keys to change columns", 0, 1)
  2568.   END IF
  2569.   screendone = 1
  2570.  
  2571.   fg = 8: CALL ziPublishHere(8, 2, "Drives", 2, 1): fg = 0
  2572.   LINE (10, 7)-(Xmax - 10, Ymax - 7), 4, B
  2573.  
  2574.  
  2575.   IF NoDriveSelection = 0 THEN
  2576.    dev = 0: GOSUB zzFileSelectBoxAA
  2577.  
  2578. ' find the DTA
  2579.  
  2580.    Regs.AX = &H2F00
  2581.    CALL zzBasicInt(&H21)
  2582.    DTAseg = Regs.ES
  2583.    DTAptr = Regs.BX
  2584.  
  2585. ' establish the existing devices
  2586.  
  2587.    MaxDevs = 0
  2588.    FOR i = 1 TO 26
  2589.     Devices(i) = 0
  2590.     validDevs(i) = 0
  2591.     Regs.AX = &H440E
  2592.     Regs.BX = i
  2593.     CALL zzBasicInt(&H21)
  2594.     IF (Regs.FL AND 256) = 256 THEN
  2595.      Regs.AX = 0
  2596.     END IF
  2597.     Regs.AX = Regs.AX AND 255
  2598.     IF (Regs.AX = 0) OR (Regs.AX = i) THEN
  2599.      Regs.AX = &H1C00
  2600.      Regs.DX = i
  2601.      CALL zzBasicInt(&H21)
  2602.      IF (Regs.AX AND 255) <> 255 THEN
  2603.       MaxDevs = MaxDevs + 1
  2604.       Devices(i) = MaxDevs '; set the crossreference
  2605.       validDevs(MaxDevs) = i
  2606.      END IF
  2607.     END IF
  2608.    NEXT
  2609.  
  2610. ' print the valid drives as a list
  2611.  
  2612.    fg = 0
  2613.    FOR i = 1 TO MaxDevs
  2614.     x$ = CHR$(64 + validDevs(i)) + ":"
  2615.     CALL ziPublishHere(10 + i + i, 7, x$, 1, 0)
  2616.    NEXT
  2617.   END IF
  2618.   LINE (GXloc - 16, GYloc + 8)-(GXloc, 319), 7, BF 'clear rest of list
  2619.  
  2620.  
  2621.   NoDriveSelection = 0
  2622.  
  2623.   fg = 8: CALL ziPublishHere(8, 20, "Tree", 2, 1): fg = 0
  2624.   LINE (10, 7)-(Xmax - 10, Ymax - 7), 4, B
  2625.  
  2626. ' carve off any 'wildcard' from the specified input parameter
  2627.  
  2628.   Pattern$ = UCASE$(LTRIM$(RTRIM$(Pattern$)))
  2629.   str = Pattern$
  2630.   IF INSTR(str, "?") + INSTR(str, "*") = 0 THEN
  2631.    base$ = Pattern$
  2632.    wild$ = "*.*"
  2633.   ELSE
  2634.    IF MID$(str, 2, 1) = ":" THEN
  2635.     start = 3
  2636.    ELSE
  2637.     start = 1
  2638.    END IF
  2639.    DO
  2640.     i = INSTR(start, str, "\")
  2641.     IF i <> 0 THEN
  2642.      start = i + 1
  2643.     END IF
  2644.    LOOP UNTIL i = 0
  2645.    base$ = MID$(str, 1, start - 1)
  2646.    wild$ = MID$(RTRIM$(str), start)
  2647.   END IF
  2648.  
  2649.   CALL zzValidate(base$)
  2650.   IF base$ = "?" THEN
  2651.    base$ = ""
  2652.    CALL zzChangeDir(base$)
  2653.   END IF
  2654.  
  2655.  
  2656.   IF MID$(base$, LEN(base$)) = "\" THEN
  2657.    basex$ = MID$(base$, 1, LEN(base$) - 1)
  2658.   ELSE
  2659.    basex$ = base$
  2660.   END IF
  2661.  
  2662.  
  2663.  
  2664. ' validate the "wildcard" portion
  2665.  
  2666. ' (make sure no more than one ".")
  2667.  
  2668.   i = INSTR(wild$, ".")
  2669.   IF i <> 0 THEN
  2670.    x$ = wild$
  2671.    MID$(x$, i, 1) = "+"
  2672.    IF INSTR(x$, ".") THEN
  2673.     wild$ = "*.*"
  2674.     i = 2
  2675.    END IF
  2676.   END IF
  2677.  
  2678. ' (divide it into its two component parts)
  2679.  
  2680.   IF i < 2 THEN
  2681.    wildl$ = wild$
  2682.    wildr$ = ""
  2683.   ELSE
  2684.    wildl$ = MID$(wild$, 1, i - 1)
  2685.    wildr$ = MID$(wild$, i + 1)
  2686.   END IF
  2687.   IF LEN(wildl$) > 8 OR LEN(wildr$) > 3 THEN
  2688.    wild$ = "*.*"
  2689.    wildl$ = "*"
  2690.    wildr$ = "*"
  2691.   END IF
  2692.  
  2693. ' (make sure no more than one TRAILING "*" in left part)
  2694.  
  2695.   i = INSTR(wildl$, "*")
  2696.   IF i <> 0 THEN
  2697.    IF i <> LEN(wildl$) THEN
  2698.     wild$ = "*.*"
  2699.     wildl$ = "*"
  2700.     wildr$ = "*"
  2701.    END IF
  2702.   END IF
  2703.  
  2704. ' (make sure no more than one TRAILING "*" in right part)
  2705.  
  2706.   i = INSTR(wildr$, "*")
  2707.   IF i <> 0 THEN
  2708.    IF i <> LEN(wildr$) THEN
  2709.     wild$ = "*.*"
  2710.     wildl$ = "*"
  2711.     wildr$ = "*"
  2712.    END IF
  2713.   END IF
  2714.  
  2715.   i = 39 - LEN(wild$) \ 2
  2716.   x$ = "[" + wild$ + "]"
  2717.   CALL ziPublishHere(7, i, x$, 0, 0)
  2718.  
  2719. ' determine the specified drive
  2720.  
  2721.   dev = Devices(ASC(base$) - 64)
  2722.   GOSUB zzFileSelectBoxAA
  2723.  
  2724. ' create the tree
  2725.  
  2726.   FOR i = 0 TO 11
  2727.    parts$(i) = ""
  2728.   NEXT
  2729.   x$ = basex$ + "\"
  2730.  
  2731.   levels = 0
  2732.   DO
  2733.    i = INSTR(x$, "\")
  2734.    IF i <> 0 THEN
  2735.     parts$(levels) = MID$(x$, 1, i - 1)
  2736.     levels = levels + 1
  2737.     x$ = MID$(x$, i + 1)
  2738.    END IF
  2739.   LOOP UNTIL i = 0
  2740.   parts$(0) = parts$(0) + "\"
  2741.   levels = levels - 1
  2742.  
  2743.   CALL ziPublishHere(12, 15, parts$(0), 0, 0)
  2744.  
  2745.   IF levels > 0 THEN
  2746.    FOR i = 1 TO levels
  2747.     x$ = SPACE$(i + i) + CHR$(179)
  2748.     CALL ziPublishHere(11 + i + i, 13, x$, 0, 0)
  2749.     x$ = SPACE$(i + i) + CHR$(192) + CHR$(196) + parts$(i)
  2750.     CALL ziPublishHere(12 + i + i, 13, x$, 0, 0)
  2751.    NEXT
  2752.   END IF
  2753.  
  2754.   oldtree = 255
  2755.   tree = levels
  2756.   GOSUB zzFileSelectBoxHH
  2757.  
  2758.  
  2759. ' test for subdirectories present
  2760.  
  2761.   olddline = 0
  2762.   x$ = basex$ + "\*.*"
  2763.   CALL zzSearchD(x$)
  2764.  
  2765.   IF Directories <> 0 THEN
  2766.    fg = 8: CALL ziPublishHere(8, 64, "Subdirs", 2, 1): fg = 0
  2767.    FromDir = 1
  2768.    GOSUB zzFileSelectBoxEE
  2769.   END IF
  2770.  
  2771. ' test for files present
  2772.  
  2773.   x$ = basex$ + "\" + wild$
  2774.   CALL zzSearchF(x$)
  2775.  
  2776.   IF FileNames <> 0 THEN
  2777.    fg = 8: CALL ziPublishHere(8, 51, "Files", 2, 1): fg = 0
  2778.    FromFile = 1
  2779.    GOSUB zzFileSelectBoxFF
  2780.   END IF
  2781.  
  2782. ' determine where to start
  2783.  
  2784.   IF FileNames = 0 THEN
  2785.    IF Directories = 0 THEN
  2786.     fg = 4: CALL ziPublishHere(8, 20, "Tree", 2, 1): fg = 0
  2787.     Stuff$ = basex$ + "\"
  2788.     GOSUB zzFileSelectBoxDD
  2789.     Column = 2
  2790.    ELSE
  2791.     fg = 4: CALL ziPublishHere(8, 64, "Subdirs", 2, 1): fg = 0
  2792.     dline = 1
  2793.     GOSUB zzFileSelectBoxBB
  2794.     Stuff$ = basex$ + "\" + Directories$(FromDir)
  2795.     GOSUB zzFileSelectBoxDD
  2796.     Column = 4
  2797.    END IF
  2798.  
  2799.   ELSE
  2800.    fg = 4: CALL ziPublishHere(8, 51, "Files", 2, 1): fg = 0
  2801.    fline = 1
  2802.    GOSUB zzFileSelectBoxCC
  2803.    Column = 3
  2804.   END IF
  2805.  
  2806.  
  2807. ' determine what to do, based on keystroke
  2808.  
  2809.   DO
  2810.    stroke$ = "X"
  2811.    DO
  2812.     stroke$ = INKEY$
  2813.    LOOP UNTIL LEN(stroke$) = 0
  2814.    DO
  2815.     stroke$ = INKEY$
  2816.    LOOP WHILE LEN(stroke$) = 0
  2817.    IF LEN(stroke$) = 1 THEN
  2818.     stroke$ = UCASE$(stroke$)
  2819.     SELECT CASE ASC(stroke$)
  2820.     CASE 27   'ESC
  2821.      Pattern$ = "?"
  2822.      RETURN
  2823.     CASE 13   'Enter
  2824.      SELECT CASE Column
  2825.      CASE 1    'enactivate new drive
  2826.       x$ = CHR$(validDevs(dev) + 64) + ":"
  2827.       Pattern$ = x$ + "\" + wild$
  2828.       LINE (112, 88)-(383, 319), 7, BF  'clear the "tree" area
  2829.  
  2830.  
  2831.       GOSUB zzFileSelectBoxII
  2832.       GOTO zzFileSelectBoxProcess
  2833.  
  2834.      CASE 2    'choose new directory
  2835.       IF tree <> levels THEN
  2836.        base$ = ""
  2837.        FOR i = 0 TO tree
  2838.     base$ = base$ + parts$(i)
  2839.     IF MID$(base$, LEN(base$)) <> "\" THEN
  2840.      base$ = base$ + "\"
  2841.     END IF
  2842.        NEXT
  2843.        IF MID$(base$, LEN(base$)) <> "\" THEN
  2844.     base$ = base$ + "\"
  2845.        END IF
  2846.        Pattern$ = base$ + wild$
  2847.        NoDriveSelection = 1
  2848.        GOSUB zzFileSelectBoxII
  2849.        GOTO zzFileSelectBoxProcess
  2850.       END IF
  2851.  
  2852.  
  2853.      CASE 3    'exit with chosen filename
  2854.       Pattern$ = Stuff$
  2855.       RETURN
  2856.  
  2857.      CASE 4    'choose new subdirectory
  2858.       Pattern$ = basex$ + "\" + Directories$(FromDir + dline - 1)
  2859.       Pattern$ = Pattern$ + "\" + wild$
  2860.       NoDriveSelection = 1
  2861.       GOSUB zzFileSelectBoxII
  2862.       GOTO zzFileSelectBoxProcess
  2863.  
  2864.  
  2865.      END SELECT
  2866.  
  2867.     CASE ASC("A") TO ASC("Z")
  2868.      SELECT CASE Column
  2869.      CASE 1
  2870.       i = ASC(stroke$) - 64
  2871.       IF Devices(i) <> 0 THEN
  2872.        dev = Devices(i)
  2873.        GOSUB zzFileSelectBoxAA
  2874.       END IF
  2875.      CASE 3
  2876.       i = FileNames
  2877.       x$ = MID$(FileNames$(i), 1, 1)
  2878.       IF x$ >= stroke$ THEN
  2879.        i = 0
  2880.        DO
  2881.     i = i + 1
  2882.     x$ = MID$(FileNames$(i), 1, 1)
  2883.        LOOP WHILE x$ < stroke$
  2884.       END IF
  2885.       FromFile = i
  2886.       GOSUB zzFileSelectBoxFF
  2887.       fline = 1: GOSUB zzFileSelectBoxCC
  2888.  
  2889.      CASE 4
  2890.       i = Directories
  2891.       x$ = MID$(Directories$(i), 1, 1)
  2892.       IF x$ >= stroke$ THEN
  2893.        i = 0
  2894.        DO
  2895.     i = i + 1
  2896.     x$ = MID$(Directories$(i), 1, 1)
  2897.        LOOP WHILE x$ < stroke$
  2898.       END IF
  2899.       FromDir = i
  2900.       GOSUB zzFileSelectBoxEE
  2901.       dline = 1: GOSUB zzFileSelectBoxBB
  2902.  
  2903.      END SELECT
  2904.     END SELECT
  2905.    ELSE
  2906.     SELECT CASE MID$(stroke$, 2)
  2907.     CASE "I"    'Page UP
  2908.      SELECT CASE Column
  2909.      CASE 3
  2910.       OldFromFile = FromFile
  2911.       IF FromFile + fline > 31 THEN
  2912.        FromFile = FromFile + fline - 31
  2913.       ELSE
  2914.        FromFile = 1
  2915.       END IF
  2916.       IF OldFromFile <> FromFile THEN GOSUB zzFileSelectBoxFF
  2917.       fline = 1: GOSUB zzFileSelectBoxCC
  2918.      CASE 4
  2919.       OldFromDir = FromDir
  2920.       IF FromDir + dline > 31 THEN
  2921.        FromDir = FromDir + dline - 31
  2922.       ELSE
  2923.        FromDir = 1
  2924.       END IF
  2925.       IF OldFromDir <> FromDir THEN GOSUB zzFileSelectBoxEE
  2926.       dline = 1: GOSUB zzFileSelectBoxBB
  2927.      END SELECT
  2928.     CASE "Q"    'Page DN
  2929.      SELECT CASE Column
  2930.      CASE 3
  2931.       OldFromFile = FromFile
  2932.       IF FromFile + fline + 30 < FileNames THEN
  2933.        FromFile = FromFile + fline + 29
  2934.        IF OldFromFile <> FromFile THEN GOSUB zzFileSelectBoxFF
  2935.        fline = 1: GOSUB zzFileSelectBoxCC
  2936.       END IF
  2937.      CASE 4
  2938.       OldFromDir = FromDir
  2939.       IF FromDir + dline + 30 < Directories THEN
  2940.        FromDir = FromDir + dline + 29
  2941.        IF OldFromDir <> FromDir THEN GOSUB zzFileSelectBoxEE
  2942.        dline = 1: GOSUB zzFileSelectBoxBB
  2943.       END IF
  2944.      END SELECT
  2945.     CASE "G"    'HOME
  2946.      SELECT CASE Column
  2947.      CASE 3
  2948.       IF FromFile <> 1 THEN
  2949.        FromFile = 1
  2950.        GOSUB zzFileSelectBoxFF
  2951.       END IF
  2952.       fline = 1: GOSUB zzFileSelectBoxCC
  2953.      CASE 4
  2954.       IF FromDir <> 1 THEN
  2955.        FromDir = 1
  2956.        GOSUB zzFileSelectBoxEE
  2957.       END IF
  2958.       dline = 1: GOSUB zzFileSelectBoxBB
  2959.      END SELECT
  2960.     CASE "O"    'END
  2961.      SELECT CASE Column
  2962.      CASE 3
  2963.       OldFromFile = FromFile
  2964.       FromFile = FileNames - 29
  2965.       IF FromFile < 1 THEN
  2966.        FromFile = 1
  2967.       END IF
  2968.       IF OldFromFile <> FromFile THEN GOSUB zzFileSelectBoxFF
  2969.       fline = 1: GOSUB zzFileSelectBoxCC
  2970.      CASE 4
  2971.       OldFromDir = FromDir
  2972.       FromDir = Directories - 29
  2973.       IF FromDir < 1 THEN
  2974.        FromDir = 1
  2975.       END IF
  2976.       IF OldFromDir <> FromDir THEN GOSUB zzFileSelectBoxEE
  2977.       dline = 1: GOSUB zzFileSelectBoxBB
  2978.      END SELECT
  2979.     CASE "H"    'UP
  2980.      SELECT CASE Column
  2981.      CASE 1     'drives
  2982.       IF dev > 1 THEN
  2983.        dev = dev - 1
  2984.        GOSUB zzFileSelectBoxAA
  2985.       END IF
  2986.      CASE 2     'tree
  2987.       IF tree > 0 THEN
  2988.        tree = tree - 1
  2989.        GOSUB zzFileSelectBoxHH
  2990.       END IF
  2991.      CASE 3     'files
  2992.       i = FromFile + fline - 2
  2993.       IF i > 0 THEN
  2994.        IF fline > 1 THEN
  2995.     fline = fline - 1
  2996.     GOSUB zzFileSelectBoxCC
  2997.        ELSE
  2998.     OldFromFile = FromFile
  2999.     FromFile = FromFile - 30
  3000.     fline = fline + 29
  3001.     IF FromFile < 1 THEN
  3002.      fline = fline + FromFile - 1
  3003.      FromFile = 1
  3004.     END IF
  3005.     IF OldFromFile <> FromFile THEN GOSUB zzFileSelectBoxFF
  3006.     GOSUB zzFileSelectBoxCC
  3007.        END IF
  3008.       END IF
  3009.      CASE 4     'subdirs
  3010.       i = FromDir + dline - 2
  3011.       IF i > 0 THEN
  3012.        IF dline > 1 THEN
  3013.     dline = dline - 1
  3014.     GOSUB zzFileSelectBoxBB
  3015.        ELSE
  3016.     OldFromDir = FromDir
  3017.     FromDir = FromDir - 30
  3018.     dline = dline + 29
  3019.     IF FromDir < 1 THEN
  3020.      dline = dline + FromDir - 1
  3021.      FromDir = 1
  3022.     END IF
  3023.     IF OldFromDir <> FromDir THEN GOSUB zzFileSelectBoxEE
  3024.     GOSUB zzFileSelectBoxBB
  3025.        END IF
  3026.       END IF
  3027.      END SELECT
  3028.  
  3029.     CASE "P"   'DOWN
  3030.      SELECT CASE Column
  3031.      CASE 1     'drives
  3032.       IF dev < MaxDevs THEN
  3033.        dev = dev + 1
  3034.        GOSUB zzFileSelectBoxAA
  3035.       END IF
  3036.      CASE 2     'tree
  3037.       IF tree < levels THEN
  3038.        tree = tree + 1
  3039.        GOSUB zzFileSelectBoxHH
  3040.       END IF
  3041.      CASE 3     'files
  3042.       i = FromFile + fline
  3043.       IF i <= FileNames THEN
  3044.        IF fline < 30 THEN
  3045.     fline = fline + 1
  3046.     GOSUB zzFileSelectBoxCC
  3047.        ELSE
  3048.     FromFile = i: GOSUB zzFileSelectBoxFF
  3049.     fline = 1: GOSUB zzFileSelectBoxCC
  3050.        END IF
  3051.       END IF
  3052.      CASE 4     'subdirs
  3053.       i = FromDir + dline
  3054.       IF i <= Directories THEN
  3055.        IF dline < 30 THEN
  3056.     dline = dline + 1
  3057.     GOSUB zzFileSelectBoxBB
  3058.        ELSE
  3059.     FromDir = i: GOSUB zzFileSelectBoxEE
  3060.     dline = 1: GOSUB zzFileSelectBoxBB
  3061.        END IF
  3062.       END IF
  3063.      END SELECT
  3064.     CASE "K"   'LEFT
  3065.      SELECT CASE Column
  3066.      CASE 2     'from TREE to DRIVES
  3067.       tree = levels
  3068.       GOSUB zzFileSelectBoxHH
  3069.       fg = 8: CALL ziPublishHere(8, 20, "Tree", 2, 1)
  3070.       fg = 4: CALL ziPublishHere(8, 2, "Drives", 2, 1): fg = 0
  3071.       LINE (10, 7)-(Xmax - 10, Ymax - 7), 4, B
  3072.       Column = 1
  3073.      CASE 3     'from FILES to TREE
  3074.       fg = 8: CALL ziPublishHere(8, 51, "Files", 2, 1)
  3075.       fg = 4: CALL ziPublishHere(8, 20, "Tree", 2, 1): fg = 0
  3076.       Column = 2
  3077.      CASE 4     'from SUBDIRS to ?
  3078.       dline = 0: GOSUB zzFileSelectBoxBB
  3079.       fg = 8: CALL ziPublishHere(8, 64, "Subdirs", 2, 1): fg = 4
  3080.       IF FileNames = 0 THEN
  3081.        CALL ziPublishHere(8, 20, "Tree", 2, 1)
  3082.        Column = 2
  3083.       ELSE
  3084.        CALL ziPublishHere(8, 51, "Files", 2, 1)
  3085.        Column = 3
  3086.       END IF
  3087.       fg = 0
  3088.      END SELECT
  3089.  
  3090.     CASE "M"   'RIGHT
  3091.      SELECT CASE Column
  3092.      CASE 1     'from DRIVES to TREE
  3093.       dev = Devices(ASC(base$) - 64)
  3094.       GOSUB zzFileSelectBoxAA     'return to original drive
  3095.       fg = 8: CALL ziPublishHere(8, 2, "Drives", 2, 1)
  3096.       fg = 15: LINE (10, 7)-(Xmax - 10, Ymax - 7), 4, B
  3097.       fg = 4: CALL ziPublishHere(8, 20, "Tree", 2, 1): fg = 0
  3098.       Column = 2
  3099.      CASE 2     'from TREE to ?
  3100.       tree = levels
  3101.       GOSUB zzFileSelectBoxHH
  3102.       IF FileNames = 0 THEN
  3103.        IF Directories <> 0 THEN
  3104.     fg = 8: CALL ziPublishHere(8, 20, "Tree", 2, 1)
  3105.     fg = 4: CALL ziPublishHere(8, 64, "Subdirs", 2, 1): fg = 0
  3106.     dline = 1: GOSUB zzFileSelectBoxBB
  3107.     Column = 4
  3108.        END IF
  3109.       ELSE
  3110.        fg = 8: CALL ziPublishHere(8, 20, "Tree", 2, 1)
  3111.        fg = 4: CALL ziPublishHere(8, 51, "Files", 2, 1): fg = 0
  3112.        Column = 3
  3113.       END IF
  3114.      CASE 3     'from FILES to SUBDIRS (if possible)
  3115.       IF Directories <> 0 THEN
  3116.        fg = 8: CALL ziPublishHere(8, 51, "Files", 2, 1)
  3117.        fg = 4: CALL ziPublishHere(8, 64, "Subdirs", 2, 1): fg = 0
  3118.        dline = 1: GOSUB zzFileSelectBoxBB
  3119.        Column = 4
  3120.       END IF
  3121.      END SELECT
  3122.     END SELECT
  3123.    END IF
  3124.  
  3125.   LOOP
  3126.  
  3127. '   ╔════════════════╗
  3128. '   ║      AA        ╟─────────────────────────────────────────────┐
  3129. '   ╚╤═══════════════╝                                             │
  3130. '    │         change the cursor bar on "dev"                      │
  3131. '    │                                                             │
  3132. '    │         input: dev   output: olddev                         │
  3133. '    └─────────────────────────────────────────────────────────────┘
  3134. zzFileSelectBoxAA:
  3135.  IF dev <> olddev THEN
  3136.   FromRow = 10 + olddev + olddev
  3137.   ToRow = FromRow
  3138.   FromCol = 5
  3139.   ToCol = 10
  3140.   swap1 = bg: swap2 = fg
  3141.   IF olddev > 0 THEN
  3142.    GOSUB zzFileSelectBoxGG
  3143.   END IF
  3144.   FromRow = 10 + dev + dev
  3145.   ToRow = FromRow
  3146.   olddev = dev
  3147.   IF olddev > 0 THEN
  3148.    GOSUB zzFileSelectBoxGG
  3149.   END IF
  3150.  END IF
  3151.  RETURN
  3152.  
  3153.  
  3154.  
  3155. '   ╔════════════════╗
  3156. '   ║      BB        ╟─────────────────────────────────────────────┐
  3157. '   ╚╤═══════════════╝                                             │
  3158. '    │         change the cursor bar on "dline"                    │
  3159. '    │                                                             │
  3160. '    │         input: dline   output: olddline                     │
  3161. '    └─────────────────────────────────────────────────────────────┘
  3162. zzFileSelectBoxBB:
  3163.  IF dline <> olddline THEN
  3164.   FromRow = 10 + olddline
  3165.   ToRow = FromRow
  3166.   FromCol = 67
  3167.   ToCol = 78
  3168.   swap1 = bg: swap2 = fg
  3169.   IF olddline > 0 THEN GOSUB zzFileSelectBoxGG
  3170.   FromRow = 10 + dline
  3171.   ToRow = FromRow
  3172.   olddline = dline
  3173.   IF dline > 0 THEN GOSUB zzFileSelectBoxGG
  3174.  END IF
  3175.  RETURN
  3176.  
  3177.  
  3178.  
  3179. '   ╔════════════════╗
  3180. '   ║      CC        ╟─────────────────────────────────────────────┐
  3181. '   ╚╤═══════════════╝                                             │
  3182. '    │         change the cursor bar on "fline"                    │
  3183. '    │                                                             │
  3184. '    │         input: fline   output: oldfline                     │
  3185. '    └─────────────────────────────────────────────────────────────┘
  3186. zzFileSelectBoxCC:
  3187.  IF fline <> oldfline THEN
  3188.   FromRow = 10 + oldfline
  3189.   ToRow = FromRow
  3190.   FromCol = 51
  3191.   ToCol = 62
  3192.   swap1 = bg: swap2 = fg
  3193.   IF oldfline > 0 THEN
  3194.    GOSUB zzFileSelectBoxGG
  3195.   END IF
  3196.   FromRow = 10 + fline
  3197.   ToRow = FromRow
  3198.   oldfline = fline
  3199.   GOSUB zzFileSelectBoxGG
  3200.   Stuff$ = basex$ + "\" + FileNames$(FromFile + fline - 1)
  3201.   GOSUB zzFileSelectBoxDD
  3202.  END IF
  3203.  RETURN
  3204.  
  3205.  
  3206. '   ╔════════════════╗
  3207. '   ║      DD        ╟─────────────────────────────────────────────┐
  3208. '   ╚╤═══════════════╝                                             │
  3209. '    │     Determine middle of line for publishing "Stuff$"        │
  3210. '    │                                                             │
  3211. '    │                                                             │
  3212. '    └─────────────────────────────────────────────────────────────┘
  3213. zzFileSelectBoxDD:
  3214.  LINE (38, 26)-(601, 46), 3, BF
  3215.  LINE (38, 26)-(601, 46), 8, B
  3216.  CALL ziPublishHere(5, 40 - LEN(Stuff$) \ 2, Stuff$, 1, 2)
  3217.  
  3218.  RETURN
  3219.  
  3220.  
  3221.  
  3222. '   ╔════════════════╗
  3223. '   ║      EE        ╟─────────────────────────────────────────────┐
  3224. '   ╚╤═══════════════╝                                             │
  3225. '    │         Show 30 subdirectories                              │
  3226. '    │                                                             │
  3227. '    │   input: FromDir                                            │
  3228. '    │                                                             │
  3229. '    │                                                             │
  3230. '    └─────────────────────────────────────────────────────────────┘
  3231. zzFileSelectBoxEE:
  3232.  
  3233.  LINE (512, 80)-(Xmax - 11, 319), 7, BF
  3234.  IF FromDir > Directories THEN RETURN
  3235.  IF FromDir > 1 THEN
  3236.   fg = 4: CALL ziPublishHere(11, 65, CHR$(24), 0, 0): fg = 0
  3237.  END IF
  3238.  IF FromDir + 30 <= Directories THEN
  3239.   fg = 4: CALL ziPublishHere(40, 65, CHR$(25), 0, 0): fg = 0
  3240.   j = FromDir + 29
  3241.  ELSE
  3242.   j = Directories
  3243.  END IF
  3244.  
  3245.  FOR i = FromDir TO j
  3246.   k = INSTR(Directories$(i), ".")
  3247.   IF k = 0 THEN
  3248.    x$ = Directories$(i)
  3249.   ELSE
  3250.    x$ = MID$(Directories$(i), 1, k - 1) + SPACE$(8)
  3251.    x$ = MID$(x$, 1, 9) + MID$(Directories$(i), k + 1)
  3252.   END IF
  3253.   CALL ziPublishHere(11 + i - FromDir, 67, x$, 0, 1)
  3254.  NEXT
  3255.  olddline = 0
  3256.  
  3257.  RETURN
  3258.  
  3259.  
  3260. '   ╔════════════════╗
  3261. '   ║      FF        ╟─────────────────────────────────────────────┐
  3262. '   ╚╤═══════════════╝                                             │
  3263. '    │         Show 30 filenames                                   │
  3264. '    │                                                             │
  3265. '    │   input: FromFile                                           │
  3266. '    │                                                             │
  3267. '    │                                                             │
  3268. '    └─────────────────────────────────────────────────────────────┘
  3269. zzFileSelectBoxFF:
  3270.  
  3271.  LINE (384, 80)-(495, 319), 7, BF
  3272.  IF FromFile > FileNames THEN RETURN
  3273.  IF FromFile > 1 THEN
  3274.   fg = 4: CALL ziPublishHere(11, 49, CHR$(24), 0, 0): fg = 0
  3275.  END IF
  3276.  IF FromFile + 30 <= FileNames THEN
  3277.   fg = 4: CALL ziPublishHere(40, 49, CHR$(25), 0, 0): fg = 0
  3278.   j = FromFile + 29
  3279.  ELSE
  3280.   j = FileNames
  3281.  END IF
  3282.  
  3283.  FOR i = FromFile TO j
  3284.   k = INSTR(FileNames$(i), ".")
  3285.   IF k = 0 THEN
  3286.    x$ = FileNames$(i)
  3287.   ELSE
  3288.    x$ = MID$(FileNames$(i), 1, k - 1) + SPACE$(8)
  3289.    x$ = MID$(x$, 1, 9) + MID$(FileNames$(i), k + 1)
  3290.   END IF
  3291.   CALL ziPublishHere(11 + i - FromFile, 51, x$, 0, 0)
  3292.  NEXT
  3293.  oldfline = 0
  3294.  
  3295.  RETURN
  3296.  
  3297.  
  3298. '   ╔════════════════╗
  3299. '   ║      GG        ╟─────────────────────────────────────────────┐
  3300. '   ╚╤═══════════════╝                                             │
  3301. '    │         Swap the colours (swap1 and swap2) of a region      │
  3302. '    │                                                             │
  3303. '    │  input: FromCol, FromRow, ToCol, ToRow, swap1, swap2        │
  3304. '    │                                                             │
  3305. '    │                                                             │
  3306. '    └─────────────────────────────────────────────────────────────┘
  3307. zzFileSelectBoxGG:
  3308.  fx = FromCol * 8 - 8
  3309.  fy = FromRow * 8 - 8
  3310.  tx = ToCol * 8 - 1
  3311.  ty = ToRow * 8 - 1
  3312.  FOR ix = fx TO tx
  3313.   FOR iy = fy TO ty
  3314.    SELECT CASE POINT(ix, iy)
  3315.    CASE swap1
  3316.     PSET (ix, iy), swap2
  3317.    CASE swap2
  3318.     PSET (ix, iy), swap1
  3319.    END SELECT
  3320.   NEXT
  3321.  NEXT
  3322.  RETURN
  3323.  
  3324. '   ╔════════════════╗
  3325. '   ║      HH        ╟─────────────────────────────────────────────┐
  3326. '   ╚╤═══════════════╝                                             │
  3327. '    │         change the cursor bar on "tree"                     │
  3328. '    │                                                             │
  3329. '    │         input: tree   output: oldtree                       │
  3330. '    └─────────────────────────────────────────────────────────────┘
  3331. zzFileSelectBoxHH:
  3332.  IF tree <> oldtree THEN
  3333.   FromRow = 12 + oldtree + oldtree
  3334.   ToRow = FromRow
  3335.   FromCol = 15 + oldtree + oldtree
  3336.   ToCol = FromCol + 11
  3337.   swap1 = bg: swap2 = fg
  3338.   IF oldtree <> 255 THEN
  3339.    GOSUB zzFileSelectBoxGG
  3340.   END IF
  3341.   FromRow = 12 + tree + tree
  3342.   ToRow = FromRow
  3343.   FromCol = 15 + tree + tree
  3344.   ToCol = FromCol + 11
  3345.   oldtree = tree
  3346.   GOSUB zzFileSelectBoxGG
  3347.  END IF
  3348.  RETURN
  3349.  
  3350.  
  3351. '   ╔════════════════╗
  3352. '   ║      II        ╟─────────────────────────────────────────────┐
  3353. '   ╚╤═══════════════╝                                             │
  3354. '    │         clear screen areas when changing directory          │
  3355. '    │                                                             │
  3356. '    │                                                             │
  3357. '    └─────────────────────────────────────────────────────────────┘
  3358. zzFileSelectBoxII:
  3359.  oldtree = 255
  3360.  oldfline = 0
  3361.  olddline = 0
  3362.  LINE (112, 16 * tree + 80)-(383, 319), 7, BF
  3363.  LINE (384, 56)-(495, 319), 7, BF
  3364.  LINE (504, 56)-(Xmax - 11, 319), 7, BF
  3365.  Stuff$ = "(Please Wait)"
  3366.  fg = 14: GOSUB zzFileSelectBoxDD: fg = 0
  3367.  RETURN
  3368.  
  3369. END SUB
  3370.  
  3371. '<p>
  3372. '++++++++++++++++++++++++
  3373. SUB zzInPath (Field$)
  3374.  
  3375.   x$ = ".;" + ENVIRON$("PATH")
  3376.   IF RIGHT$(x$, 1) <> ";" THEN x$ = x$ + ";"
  3377.   i = 1
  3378.   DO
  3379.     j = INSTR(i, x$, ";")
  3380.     IF j THEN
  3381.       y$ = UCASE$(MID$(x$, i, j - i))
  3382.       i = j + 1
  3383.       IF RIGHT$(y$, 1) <> "\" THEN y$ = y$ + "\"
  3384.       F$ = y$ + Field$
  3385.       Bad = 0
  3386.       OPEN "I", 1, F$
  3387.       IF Bad = 0 THEN
  3388.     CLOSE 1
  3389.     EXIT DO
  3390.       END IF
  3391.       F$ = ""
  3392.     END IF
  3393.   LOOP WHILE j
  3394.   Bad = 0
  3395.   Field$ = F$
  3396.  
  3397. END SUB
  3398.  
  3399. '<p>
  3400. '++++++++++++++++++++++++
  3401. SUB zzSearchD (Pattern$)
  3402.  
  3403. DIM str AS STRING * 65
  3404.  
  3405.  CALL zzCritOff
  3406.  GOSUB zzSearchDProcess
  3407.  CALL zzCritOn
  3408.  
  3409.  EXIT SUB
  3410.  
  3411. zzSearchDProcess:
  3412.   upperbound = UBOUND(Directories$)
  3413.   str = LTRIM$(RTRIM$(UCASE$(Pattern$)))
  3414.   Pattern$ = "?"
  3415.  
  3416. ' clear the Directories$ array
  3417.  
  3418.  FOR i = 1 TO 500
  3419.   Directories$(i) = ""
  3420.  NEXT
  3421.  Directories = 0
  3422.  
  3423. ' locate the DTA
  3424.  
  3425.  Regs.AX = &H2F00
  3426.  CALL zzBasicInt(&H21)
  3427.  DTAseg = Regs.ES
  3428.  DTAptr = Regs.BX
  3429.  
  3430. ' confirm that the drive (if specified) is valid
  3431.  
  3432.  IF MID$(str, 2, 1) = ":" THEN
  3433.   i = ASC(str)
  3434.   IF i < 65 THEN RETURN
  3435.   IF i > 90 THEN RETURN
  3436.   Regs.AX = &H440E
  3437.   Regs.BX = i - 64
  3438.   CALL zzBasicInt(&H21)
  3439.   IF (Regs.FL AND 256) <> 256 THEN
  3440.    j = Regs.AX AND 255
  3441.    IF (j <> 0) AND (j <> i - 64) THEN
  3442.     i = j + 64
  3443.    END IF
  3444.   END IF
  3445.   Regs.AX = &H1C00
  3446.   Regs.DX = i - 64
  3447.   CALL zzBasicInt(&H21)
  3448.   IF (Regs.AX AND 255) = 255 THEN RETURN
  3449.  END IF
  3450.  
  3451.  x$ = RTRIM$(str)
  3452.  IF (x$ = "") OR (MID$(x$, 2) = ":") THEN
  3453.   x$ = x$ + "*.*"
  3454.  END IF
  3455.  IF (MID$(x$, LEN(x$)) = "\") THEN
  3456.   x$ = x$ + "*.*"
  3457.  END IF
  3458.  
  3459.  IF INSTR(x$, "*") + INSTR(x$, "?") = 0 THEN
  3460.   x$ = x$ + "\*.*"
  3461.  END IF
  3462.  
  3463. ' initiate the search
  3464.  
  3465.  Pattern$ = x$
  3466.  str = x$ + CHR$(0)
  3467.  Regs.AX = &H4E00
  3468.  Regs.CX = &H10
  3469.  Regs.DS = VARSEG(str)
  3470.  Regs.DX = VARPTR(str)
  3471.  CALL zzBasicInt(&H21)
  3472.  
  3473.  DO WHILE (Regs.FL AND 256) = 0
  3474.   DEF SEG = DTAseg
  3475.  
  3476. ' pull the name (letter by letter) from the DTA
  3477.  
  3478.   IF (PEEK(DTAptr + &H15) AND &H10) = &H10 THEN
  3479.    Name$ = ""
  3480.    i = &H1E
  3481.    DO
  3482.     j = PEEK(DTAptr + i)
  3483.     IF j <> 0 THEN
  3484.      Name$ = Name$ + CHR$(j)
  3485.     END IF
  3486.     i = i + 1
  3487.    LOOP UNTIL j = 0
  3488.  
  3489. ' omit "." and ".."
  3490.  
  3491.    IF MID$(Name$, 1, 1) <> "." THEN
  3492.     Directories = Directories + 1
  3493.     IF Directories > upperbound THEN RETURN
  3494.     Directories$(Directories) = Name$
  3495.    END IF
  3496.   END IF
  3497.  
  3498. ' keep going until all matches are found
  3499.  
  3500.   Regs.AX = &H4F00
  3501.   CALL zzBasicInt(&H21)
  3502.  LOOP
  3503.  
  3504. ' now find the first byte of the directory pattern itself
  3505.  
  3506.  IF MID$(str, 2, 1) = ":" THEN
  3507.   start = 3
  3508.  ELSE
  3509.   start = 1
  3510.  END IF
  3511.  DO
  3512.   i = INSTR(start, str, "\")
  3513.   IF i <> 0 THEN
  3514.    start = i + 1
  3515.   END IF
  3516.  LOOP UNTIL i = 0
  3517.  x$ = MID$(str, 1, start - 1)
  3518.  CALL zzValidate(x$)
  3519.  IF MID$(x$, LEN(x$)) <> "\" THEN x$ = x$ + "\"
  3520.  i = INSTR(str, CHR$(0))
  3521.  
  3522.  Pattern$ = RTRIM$(x$ + MID$(str, start, i - start))
  3523.  
  3524.  IF Directories <> 0 THEN
  3525.   SortCount = Directories
  3526.   CALL zzAlphaSort(Directories$())
  3527.  END IF
  3528.  RETURN
  3529. END SUB
  3530.  
  3531. '<p>
  3532. '++++++++++++++++++++++++
  3533. SUB zzSearchF (Pattern$)
  3534.  
  3535. DIM str AS STRING * 65
  3536.  
  3537.  CALL zzCritOff
  3538.  GOSUB zzSearchFProcess
  3539.  CALL zzCritOn
  3540.  
  3541.  EXIT SUB
  3542.  
  3543. zzSearchFProcess:
  3544.  upperbound = UBOUND(FileNames$)
  3545.  str = LTRIM$(RTRIM$(UCASE$(Pattern$)))
  3546.  Pattern$ = "?"
  3547.  
  3548. ' clear the FileNames$ array
  3549.  
  3550.  FOR i = 1 TO 500
  3551.   FileNames$(i) = ""
  3552.  NEXT
  3553.  FileNames = 0
  3554.  
  3555. ' locate the DTA
  3556.  
  3557.  Regs.AX = &H2F00
  3558.  CALL zzBasicInt(&H21)
  3559.  DTAseg = Regs.ES
  3560.  DTAptr = Regs.BX
  3561.  
  3562. ' confirm that the drive (if specified) is valid
  3563.  
  3564.  IF MID$(str, 2, 1) = ":" THEN
  3565.   i = ASC(str)
  3566.   IF i < 65 THEN RETURN
  3567.   IF i > 90 THEN RETURN
  3568.   Regs.AX = &H440E
  3569.   Regs.BX = i - 64
  3570.   CALL zzBasicInt(&H21)
  3571.   IF (Regs.FL AND 256) <> 256 THEN
  3572.    j = Regs.AX AND 255
  3573.    IF (j <> 0) AND (j <> i - 64) THEN
  3574.     i = j + 64
  3575.    END IF
  3576.   END IF
  3577.   Regs.AX = &H1C00
  3578.   Regs.DX = i - 64
  3579.   CALL zzBasicInt(&H21)
  3580.   IF (Regs.AX AND 255) = 255 THEN RETURN
  3581.  END IF
  3582.  
  3583.  x$ = RTRIM$(str)
  3584.  IF (x$ = "") OR (MID$(x$, 2) = ":") THEN
  3585.   x$ = x$ + "*.*"
  3586.  END IF
  3587.  IF (MID$(x$, LEN(x$)) = "\") THEN
  3588.   x$ = x$ + "*.*"
  3589.  END IF
  3590.  
  3591.  IF INSTR(x$, "*") + INSTR(x$, "?") = 0 THEN
  3592.   x$ = x$ + "\*.*"
  3593.  END IF
  3594.  
  3595. ' initiate the search
  3596.  
  3597.  Pattern$ = x$
  3598.  str = x$ + CHR$(0)
  3599.  Regs.AX = &H4E00
  3600.  Regs.CX = &H27
  3601.  Regs.DS = VARSEG(str)
  3602.  Regs.DX = VARPTR(str)
  3603.  CALL zzBasicInt(&H21)
  3604.  
  3605.  DO WHILE (Regs.FL AND 256) = 0
  3606.   DEF SEG = DTAseg
  3607.  
  3608. ' pull the name (letter by letter) from the DTA
  3609.  
  3610.   Name$ = ""
  3611.   i = &H1E
  3612.   DO
  3613.    j = PEEK(DTAptr + i)
  3614.    IF j <> 0 THEN
  3615.     Name$ = Name$ + CHR$(j)
  3616.    END IF
  3617.    i = i + 1
  3618.   LOOP UNTIL j = 0
  3619.  
  3620.   FileNames = FileNames + 1
  3621.   IF FileNames > upperbound THEN RETURN
  3622.   FileNames$(FileNames) = Name$
  3623.  
  3624.   Regs.AX = &H4F00
  3625.   CALL zzBasicInt(&H21)
  3626.  LOOP
  3627.  
  3628.  
  3629. ' now find the first byte of the file pattern itself
  3630.  
  3631.  IF MID$(str, 2, 1) = ":" THEN
  3632.   start = 3
  3633.  ELSE
  3634.   start = 1
  3635.  END IF
  3636.  DO
  3637.   i = INSTR(start, str, "\")
  3638.   IF i <> 0 THEN
  3639.    start = i + 1
  3640.   END IF
  3641.  LOOP UNTIL i = 0
  3642.  x$ = MID$(str, 1, start - 1)
  3643.  CALL zzValidate(x$)
  3644.  IF MID$(x$, LEN(x$)) <> "\" THEN x$ = x$ + "\"
  3645.  i = INSTR(str, CHR$(0))
  3646.  
  3647.  Pattern$ = RTRIM$(x$ + MID$(str, start, i - start))
  3648.  
  3649.  IF FileNames <> 0 THEN
  3650.   SortCount = FileNames
  3651.   CALL zzAlphaSort(FileNames$())
  3652.  END IF
  3653.  RETURN
  3654. END SUB
  3655.  
  3656. '<p>
  3657. '++++++++++++++++++++++++
  3658. SUB zzValidate (Directory$)
  3659.  
  3660. DIM str AS STRING * 65
  3661.  
  3662.  CALL zzCritOff
  3663.  GOSUB zzValidateProcess
  3664.  CALL zzCritOn
  3665.  
  3666.  EXIT SUB
  3667.  
  3668. zzValidateProcess:
  3669.  
  3670.  Candpath$ = LTRIM$(RTRIM$(UCASE$(Directory$)))
  3671.  IF MID$(Candpath$, LEN(Candpath$)) = "\" THEN
  3672.   IF LEN(Candpath$) > 1 THEN
  3673.    IF MID$(Candpath$, 2) <> ":\" THEN
  3674.     Candpath$ = MID$(Candpath$, 1, LEN(Candpath$) - 1)
  3675.    END IF
  3676.   END IF
  3677.  END IF
  3678.  
  3679.  Directory$ = "?"
  3680.  
  3681. ' check that any named drive is valid
  3682.  
  3683.  IF MID$(Candpath$, 2, 1) = ":" THEN
  3684.   i = ASC(MID$(Candpath$, 1, 1))
  3685.   IF i < 65 THEN RETURN
  3686.   IF i > 90 THEN RETURN
  3687.   Regs.AX = &H440E
  3688.   Regs.BX = i - 64
  3689.   CALL zzBasicInt(&H21)
  3690.   IF (Regs.FL AND 256) <> 256 THEN
  3691.    j = Regs.AX AND 255
  3692.    IF (j <> 0) AND (j <> i - 64) THEN
  3693.     i = j + 64
  3694.    END IF
  3695.   END IF
  3696.   Regs.AX = &H1C00
  3697.   Regs.DX = i - 64
  3698.   CALL zzBasicInt(&H21)
  3699.   IF (Regs.AX AND 255) = 255 THEN RETURN
  3700.  END IF
  3701.  
  3702. ' handle special case of root directory
  3703.  
  3704.  IF Candpath$ = "\" THEN
  3705.   Directory$ = ""
  3706.   CALL zzChangeDrive(Directory$)
  3707.   Directory$ = Directory$ + "\"
  3708.   RETURN
  3709.  END IF
  3710.  IF MID$(Candpath$, 2) = ":\" THEN
  3711.   Directory$ = Candpath$
  3712.   RETURN
  3713.  END IF
  3714.  
  3715. ' handle special case of NO directory
  3716.  
  3717.  IF Candpath$ = "" THEN
  3718.   CALL zzChangeDir(Candpath$)
  3719.   Directory$ = Candpath$
  3720.   RETURN
  3721.  END IF
  3722.  IF MID$(Candpath$, 2) = ":" THEN
  3723.   Regs.AX = &H4700
  3724.   Regs.DX = ASC(MID$(Candpath$, 1, 1)) - 64
  3725.   Regs.DS = VARSEG(str)
  3726.   Regs.SI = VARPTR(str)
  3727.   CALL zzBasicInt(&H21)
  3728.   i = INSTR(str, CHR$(0))
  3729.   Directory$ = Candpath$ + "\" + MID$(str, 1, i - 1)
  3730.   RETURN
  3731.  END IF
  3732.  
  3733.  str = Candpath$ + CHR$(0)
  3734.  IF INSTR(str, "*") + INSTR(str, "?") > 0 THEN RETURN
  3735.  
  3736.  
  3737. ' initiate the search
  3738.  
  3739.  Regs.AX = &H4E00
  3740.  Regs.CX = &H10
  3741.  Regs.DS = VARSEG(str)
  3742.  Regs.DX = VARPTR(str)
  3743.  CALL zzBasicInt(&H21)
  3744.  
  3745. ' abandon if not a valid directory
  3746.  
  3747.  IF (Regs.FL AND 256) <> 0 THEN RETURN
  3748. ' locate the DTA
  3749.  
  3750.  Regs.AX = &H2F00
  3751.  CALL zzBasicInt(&H21)
  3752.  DTAseg = Regs.ES
  3753.  DTAptr = Regs.BX
  3754.  
  3755.  DEF SEG = DTAseg
  3756.  attr = PEEK(DTAptr + &H15)
  3757.  IF (attr AND &H10) = 0 THEN RETURN
  3758.  
  3759. ' establish the status quo so that we can change back
  3760.  
  3761.  olddrv$ = ""
  3762.  CALL zzChangeDrive(olddrv$)
  3763.  
  3764.  IF MID$(str, 2, 1) = ":" THEN
  3765.   newdrv$ = MID$(str, 1, 2)
  3766.  ELSE
  3767.   newdrv$ = olddrv$
  3768.  END IF
  3769.  
  3770.  CALL zzChangeDrive(newdrv$)    'change to new drive
  3771.  olddir$ = ""
  3772.  CALL zzChangeDir(olddir$)      'find the current directory on new drive
  3773.  CALL zzChangeDir(str)          'change to the desired directory
  3774.  CALL zzChangeDir(olddir$)      'change back to the current directory
  3775.  CALL zzChangeDrive(olddrv$)    'change back to old drive
  3776.  IF Root = 0 THEN
  3777.   Directory$ = RTRIM$(str)
  3778.  ELSE
  3779.   Directory$ = MID$(str, 1, 2) + "\"
  3780.  END IF
  3781.  RETURN
  3782.  
  3783. END SUB
  3784.  
  3785.